Pregunta

I'm using C++03 (CUDA nvcc really, but that doesn't matter). I have the following bit of working code:

template<typename T> void baz(T*);

template<typename T>
void bar() {
    typedef void (*foo_t)(T*);
    static const foo_t dummy = baz;
    // use dummy
};

Now, I want to move the dummy variable out of the function, making it global.

First attempt:

template<typename T> void baz(T*);
template<typename T> typedef void (*foo_t)(T*);
template<typename T> const foo_t dummy = baz;

template<typename T>
void bar() {
    // use dummy
};

This doesn't work, since C++ (at least, C++03) doesn't have templated typedef:

error: "typedef" may not be specified here

error: "foo_t" is not a function or static data member

Why doesn't C++03 have this? Beats me. If I can do it in a function, I can't see why I shouldn't be able to do it outside too. I think C++11 doesn't either (but there is the templated using, right?)

Ok, so I read Template typedefs - What's your work around?, and went for the accepted answer - using a helper class.

Second Attempt:

template<typename T> void baz(T*);
template<typename T> class TemplatingHeler {
  typedef void (*foo_t)(T*);
  static const foo_t dummy = baz;
}

... this gets:

error: a member of type "void (*const)(T *)" cannot have an in-class initializer

Third Attempt:

template<typename T> void baz(T*);
template<typename T> class TemplatingHelper {
  typedef void (*foo_t)(T*);
  static foo_t dummy;
};
template<typename T> TemplatingHelper::dummy = baz;

error: name followed by "::" must be a class or namespace name

error: argument list for class template "TemplatingHelper" is missing

... and nvcc segfaults (!)

Why does all this happen, and how can I get it to work?

¿Fue útil?

Solución

Your third attempt should work, after fixing the errors ;)

template<typename T> void baz(T*);
template<typename T> class TemplatingHelper {
  typedef void (*foo_t)(T*);
  static foo_t dummy;
};

template<typename T>                   // template-declaration
typename TemplatingHelper<T>::foo_t    // type
TemplatingHelper<T>::dummy             // name
= baz;                                 // initializer

I agree it's redundant, but it follows a general form of declaration:

type name initializer ;

even though the name has already been declared and given a type inside the class template.

In this case, it's a template-declaration, so we need to add the template<typename T> part; this is required since we could also refer to a partial specialization:

template<typename T, typename U> class TemplatingHelper<T(*)(U)>
{
    typedef T(*foo_t)(U);
    static foo_t dummy;
};

template<typename T, typename U>
typename TemplatingHelper<T(*)(U)>::foo_t
TemplatingHelper<T(*)(U)>::dummy
= baz;

As the type is required and precedes the declared name, we need to explicitly state the scope where to find it:

TemplatingHelper<T>::foo_t

Unfortunately, name lookup requires to put a typename before this qualified name. See Where and why do I have to put the “template” and “typename” keywords?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top