Шаблон специализированного метода при проверке подтипа - PullRequest
0 голосов
/ 28 сентября 2018

Каков синтаксис, чтобы специализировать шаблон для метода, в то же время проверяя, существует ли какой-либо подтип?

// Syntax works fine for functions
template<class T, class... Assertions> void my_function();

template <class list_t, class list_t::value_type>
void my_function() { }

// Doesn't work for methods
class MyClass {
    template<class T, class... Assertions> void my_method();
};

// Commenting out the next two lines results in successful compile
template <class list_t, class list_t::value_type>
void MyClass::my_method() { }

int main() { }

Clang дает мне:

out-of-line definition of 'my_method' does not match any declaration in 'MyClass'

Ответы [ 3 ]

0 голосов
/ 28 сентября 2018

Синтаксис специализации следующий:

// dummy list_t...
struct list_t
{
   using value_type = int;
};

// standard implementation:
template<class T, class... Assertions>
void my_function() { }

// specialization
template <>
void my_function<list_t, list_t::value_type>() { }

class MyClass
{
    template<class T, class... Assertions>
    void my_method();
};

// standard implementation:
template<class T, class... Assertions>
void MyClass::my_method() { }

// specialisation
template <>
void MyClass::my_method<list_t, list_t::value_type>() { }
0 голосов
/ 28 сентября 2018

Мне не ясно, что именно вы хотите.

Если вы хотите, чтобы my_method() реализовывался только тогда, когда T является классом / структурой с типом value_type в нем, иВы хотите, чтобы ошибка компиляции при вызове с T без value_type содержала в себе, я предлагаю использовать SFINAE через declval() и decltype().

Что-то вроде

template <typename T>
auto my_method ()
   -> decltype( std::declval<typename T::value_type>(), void() )
 { }

Если вы можете использовать C ++ 17 вместо decltype( std::declval<typename T::value_type>(), void() ), вы можете использовать std::void_t<T::value_type>.

Если вы хотите my_method() с более общей версией и специализированной версией для классов /в структуре с value_type я предлагаю разработать общий my_method(), который просто вызывает другой метод my_method_helper(), добавляющий int значение

template <typename T>
void my_method ()
 { my_method_helper<T>(0); }

и объединяющий SFINAE и перегрузку функций для my_method_helper() с my_method_helper(), который получает long (то есть не совсем int) и когда-либо включен для более общей версии

template <typename T>
void my_method_helper (long)
 { }

и версией, которая получает ровно int (поэтому предпочтительнее, если доступно, по сравнению с long версией), но включается только тогда, когда T содержит value_type.

template <typename T>
auto my_method_helper (int)
   -> decltype( std::declval<typename T::value_type>(), void() )
 { }

Таким образом, my_method_helper(int) вызывается, когда T содержит value_type, а my_method_helper(long) вызывается иначе.

Ниже приведен полный пример компиляции (с измененными именами методов)

#include <utility>
#include <iostream>

struct MyClass
 {
   template <typename T>
   auto method_1 ()
      -> decltype( std::declval<typename T::value_type>(), void() )
    { std::cout << "method_1 " << std::endl; }

   template <typename T>
   auto method_2 (int)
      -> decltype( std::declval<typename T::value_type>(), void() )
    { std::cout << "method_2 specialized" << std::endl; }

   template <typename T>
   void method_2 (long)
    { std::cout << "method_2 generic" << std::endl; }

   template <typename T>
   void method_2 ()
    { method_2<T>(0); }
 };

struct foo
 { using value_type = int; };

int main()
 {
   MyClass mc;

   mc.method_1<foo>();
   // mc.method_1<int>(); // compilation error

   mc.method_2<foo>(); // call specialized version
   mc.method_2<int>(); // call generic version
 }

Частично не по теме: я не понимаю, что вы имеете в виду под «Синтаксис отлично работает для функций» с

template<class T, class... Assertions> void my_function();

template <class list_t, class list_t::value_type>
void my_function() { }

Как вы звоните my_function()?

0 голосов
/ 28 сентября 2018

Вы не специализируете здесь ни метод шаблона, ни функцию.Вы просто перегружаете функцию свободного шаблона и пытаетесь перегрузить метод странным образом.Чтобы заставить его работать, вы должны использовать диспетчеризацию тегов (так как частичная специализация шаблона функции невозможна в C ++) или constexpr if, если ваш компилятор поддерживает C ++ 17

...