SFINAE работает только для выводимых аргументов шаблона.В вашем случае ваш метод не зависит от какого-либо параметра из вызова метода, поэтому он не находится в выведенном контексте.Все уже известно, пока создаем экземпляр самого класса.
MSVC просто неверен в этом случае.
Обходной путь:
template<typename... Args>
class C
{
public:
template< typename U = std::tuple<Args...>>
std::enable_if_t< (std::tuple_size<U>::value > 0 ) > foo(const Args&...)
{
std::cout << "Args > 0 type " << std::endl;
}
template< typename U = std::tuple<Args...>>
std::enable_if_t< (std::tuple_size<U>::value == 0)> foo(const Args&...)
{
std::cout << "Args 0 type " << std::endl;
}
};
int main()
{
C<>{}.foo();
C<int>{}.foo(1);
}
Я не знаю, зачем вам такиеперегрузка, потому что, если список параметров пуст, вы просто должны написать перегрузку для такого без каких-либо вещей SFINAE.
, если ваш компилятор не устарел (только c ++ 14), это намного проще сиспользуя constexpr if
:
template <typename... Args>
struct C
{
void foo (const Args&... args)
{
if constexpr ( sizeof...(args) == 0)
{
std::cout << "0" << std::endl;
}
else
{
std::cout << ">0" << std::endl;
}
}
};
int main ()
{
C<> c0;
C<int> c1;
c0.foo();
c1.foo(42);
}
РЕДАКТИРОВАТЬ после комментария:
Чтобы избежать SFINAE, вы также можете использовать специализированные классы шаблонов, такие как:
// provide common stuff here
template <typename ... ARGS>
class CAll { protected: void DoSomeThing(){ std::cout << "Do some thing" << std::endl; } };
template<typename ... ARGS>
class C;
// special for no args
template<>
class C<>: public CAll<>
{
public:
void foo()
{
std::cout << "none" << std::endl;
this->DoSomeThing();
}
};
//special for at minimum one arg
template<typename FIRST, typename ... REST>
class C<FIRST, REST...>: public CAll<FIRST, REST...>
{
public:
void foo( FIRST&, REST&... )
{
std::cout << "lvalue" << std::endl;
this->DoSomeThing();
}
void foo( FIRST&&, REST&&... )
{
std::cout << "rvalue" << std::endl;
this->DoSomeThing();
}
};
int main()
{
int a;
C<>{}.foo();
C<int>{}.foo(1);
C<int>{}.foo(a);
}