Мне не ясно, что именно вы хотите.
Если вы хотите, чтобы 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()
?