Шаблонное обходное решение typedef, похоже, не работает

Я использую C++03 (CUDA nvcc действительно, но это не имеет значения). У меня есть следующий бит рабочего кода:

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

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

Теперь я хочу переместить фиктивную переменную из функции, сделав ее глобальной.

Первая попытка:

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
};

Это не работает, так как C++ (по крайней мере, C++03) не имеет шаблонного typedef:

error: "typedef" may not be specified here

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

Почему в C++ 03 этого нет? Бьет меня Если я могу сделать это в функции, я не могу понять, почему я не смогу сделать это и снаружи. Я думаю, что C++11 тоже нет (но есть шаблонные using, право?)

Итак, я прочитал Template typedefs - как вы работаете? и пошел за принятым ответом - используя вспомогательный класс.

Вторая попытка:

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

... это получает:

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

Третья попытка:

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

... и nvcc segfaults (!)

Почему все это происходит, и как я могу заставить его работать?

1 ответ

Решение

Ваша третья попытка должна сработать, после исправления ошибок;)

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

Я согласен, что это излишне, но следует общей форме декларации:

type name initializer ;

даже если имя уже объявлено и ему присвоен тип внутри шаблона класса.

В данном случае это объявление шаблона, поэтому нам нужно добавить template<typename T> часть; это необходимо, так как мы могли бы также обратиться к частичной специализации:

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;

Поскольку тип является обязательным и предшествует объявленному имени, нам нужно явно указать область, где его найти:

TemplatingHelper<T>::foo_t

К сожалению, поиск имени требует поставить typename до этого квалифицированного имени. См. Где и почему я должен поставить ключевые слова "template" и "typename"?

Другие вопросы по тегам