Явная реализация шаблона с помощью функции шаблона элемента - PullRequest
4 голосов
/ 28 августа 2010

У меня есть шаблон класса с функцией-членом шаблона.Я хочу явно создать экземпляр класса, чтобы избежать резкого замедления компиляции.Я использую g ++ 4.1.2.Я получаю неоднозначные ошибки специализации шаблона от компилятора.Это самый короткий код, который воспроизведет проблему:

template <class T, class S >
class Test
{
public:
 template< typename T1 > 
 void* get( const T1& );
 void* get(const int& ); //Specialization of the above
};

typedef Test<int, double> foo;

//instantiate
inline template class Test<int, double>;
template void* foo::get(int const&);

Я не хочу использовать универсальный метод:

template class Test<int, double>

, поскольку перегрузка get (const int &) не будетбыть определено для всех возможных явных реализаций, и, следовательно, компилятор выберет соответствие для типов, которые его не поддерживают.

Этот код компилируется в Visual Studio (без встроенного предшествующего шаблона, который является специфическим расширением gcc).Может кто-нибудь пролить свет на то, как я получаю этот фрагмент кода для компиляции?

ОБНОВЛЕНИЕ: Это ошибка, которую я получаю:

g++    -c -o template.o template.cpp
template.cpp:14: error: ambiguous template specialization ‘get<>’ for ‘void* Test<int, double>::get(const int&)’
template.cpp:7: error: candidates are: void* Test<T, S>::get(const int&) [with T = int, S = double]
template.cpp:6: error:                 template<class T1> void* Test::get(const T1&) [with T1 = T1, T = int, S = double]

ОБНОВЛЕНИЕ2: Спасибо за решение, это нескомпилировать хотя.Специализации не разрешены внутри класса.Ошибка:

g++    -c -o template.o template.cpp
template.cpp:7: error: explicit specialization in non-namespace scope ‘class Test<T, S>’
template.cpp:7: error: enclosing class templates are not explicitly specialized
template.cpp:8: error: ‘get’ is not a template function
template.cpp: In instantiation of ‘void* Test<T, S>::get(const T1&) [with T1 = int, T = int, S = double]’:
template.cpp:15:   instantiated from here
template.cpp:15: error: explicit instantiation of ‘void* Test<T, S>::get(const T1&) [with T1 = int, T = int, S = double]’ but no definition available
make: *** [template.o] Error 1

Ответы [ 2 ]

2 голосов
/ 28 августа 2010

Я запутался в этом:

Я не хочу использовать универсальный метод:

template class Test<int, double>

, поскольку перегрузка get (const int &) не будетбыть определено для всех возможных явных реализаций, и, следовательно, компилятор выберет соответствие для типов, которые его не поддерживают.

Явность одной специализации не влияет на семантику других специализаций.

Перегрузка get(const int&) - это просто функция-член, и она будет реализована для явных и неявных специализаций, как и любая другая.

Явная реализация может только замедлить компилятор.Он обрабатывает только каждое создание не более одного раза.Неиспользуемые части неявного создания экземпляров могут быть проигнорированы, но явно создавая экземпляры, вы заставляете его обрабатывать все это.В любом случае, единственное создание может занять измеримое количество времени.

Чтобы выполнить ошибки в коде:

template <class T, class S > // arguments unused
class Test
{
public:
 template< typename T1 > 
 void* get( const T1& );
 void* get(const int& ); // overload of the above
};

typedef Test<int, double> foo;

// illegal to instantiate a template before its members are defined

inline template class Test<int, double>; // "inline template" is meaningless
template void* foo::get(int const&); // typedef name "foo" cannot be used here
/* ^ illegal to explicitly instantiate a member of an already explicitly 
   instantiated template */

Обновление:

Ошибка возникает из-за не шаблонной перегрузки, не имеющей приоритета над шаблоном элемента.

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

Обходной путь # 2 - SFINAE.

 #include <boost/enable_if.hpp>
 #include <boost/type_traits.hpp>

 template< typename T1 > 
 boost::disable_if< boost::is_same<T1,int>, void* >::type
     get( const T1& ); // "turn off" declaration if in conflict

 void* get(const int& ); // unambiguous overload of the above

Если вы не можете использоватьПовышение,

 template< class T >
 struct disable_if_int { typedef void *type; };

 template<>
 struct disable_if_int<int> {};

...

 template< typename T1 > 
 disable_if_int< T1 >::type get( const T1& );

 void* get(const int& ); // unambiguous overload of the above
0 голосов
/ 28 августа 2010
template <class T, class S >
class Test
{
public:
 template< typename T1 > 
 void* get( const T1& ) { return nullptr; }

 template <>
 void* get<int>(const int& ) { return nullptr; } //Specialization of the above
};

typedef Test<int, double> foo;

int main() {
    foo lols;
    void* innit = lols.get(1);
    void* bruv = lols.get("yocakes");
}

Это прекрасно компилируется для меня на VS2010. nullptr - это c ++ 0x, но вы можете просто заменить на 0 / NULL.

...