开发者

C++ template gotchas

开发者 https://www.devze.com 2022-12-13 12:46 出处:网络
just now I had to dig through the website to find out why template class template member function was giving syntax errors:

just now I had to dig through the website to find out why template class template member function was giving syntax errors:

开发者_开发百科template<class C> class F00 {
   template<typename T> bar();
};
...
Foo<C> f;
f.bar<T>(); // syntax error here

I now realize that template brackets are treated as relational operators. To do what was intended the following bizarre syntax is needed, cf Templates: template function not playing well with class's template member function:

f.template bar<T>();

what other bizarre aspects and gotcha of C++/C++ templates you have encountered that were not something that you would consider to be common knowledge?


I got tripped up the first time I inherited a templated class from another templated class:

template<typename T>
class Base {
    int a;
};

template<typename T>
class Derived : public Base<T> {
    void func() {
        a++; // error! 'a' has not been declared
    }
};

The problem is that the compiler doesn't know if Base<T> is going to be the default template or a specialized one. A specialized version may not have int a as a member, so the compiler doesn't assume that it's available. But you can tell the compiler that it's going to be there with the using directive:

template<typename T>
class Derived : public Base<T> {
    using Base<T>::a;
    void func() {
        a++; // OK!
    }
};

Alternatively, you can make it explicit that you are using a member of T:

void func {
    T::a++; // OK!
}


This one got me upset back then:

#include <vector>
using std::vector;

struct foo {
  template<typename U>
  void vector();
};

int main() {
  foo f;
  f.vector<int>(); // ambiguous!
}

The last line in main is ambiguous, because the compiler not only looks up vector within foo, but also as an unqualified name starting from within main. So it finds both std::vector and foo::vector. To fix this, you have to write

f.foo::vector<int>();

GCC does not care about that, and accepts the above code by doing the intuitive thing (calling the member), other compilers do better and warn like comeau:

"ComeauTest.c", line 13: warning: ambiguous class member reference -- function
          template "foo::vector" (declared at line 8) used in preference to
          class template "std::vector" (declared at line 163 of
          "stl_vector.h")
        f.vector<int>(); // ambiguous!


The star of questions about templates here on SO: the missing typename!

template <typename T>
class vector
{
  public:
    typedef T * iterator;
    ...
};

template <typename T>
void func()
{
    vector<T>::iterator it;           // this is not correct!

    typename vector<T>::iterator it2; // this is correct.
}

The problem here is that vector<T>::iterator is a dependent name: it depends on a template parameter. As a consequence, the compiler does not know that iterator designates a type; we need to tell him with the typename keyword.

The same goes for template inner classes or template member/static functions: they must be disambiguated using the template keyword, as noted in the OP.

template <typename T>
void func()
{
    T::staticTemplateFunc<int>();          // ambiguous

    T::template staticTemplateFunc<int>(); // ok

    T t;

    t.memberTemplateFunc<int>();          // ambiguous

    t.template memberTemplateFunc<int>(); // ok
}


Out of scope class member function definition:

template <typename T> 
class List {                     // a namespace scope class template 
  public: 
    template <typename T2>       // a member function template 
    List (List<T2> const&);      // (constructor) 
    … 
}; 
template <typename T> 
 template <typename T2> 
List<T>::List (List<T2> const& b) // an out-of-class member function 
{                                 // template definition 
    … 
} 
0

精彩评论

暂无评论...
验证码 换一张
取 消