1

Can someone explain to me how can I check for existence of a class member function template specializations with C++17? I have tried solution from this answer and it works fine for normal functions:

template<typename, template<typename> class, typename = void_t<>>
struct detect : std::false_type {};

template<typename T, template<typename> class Op>
struct detect<T, Op, void_t<Op<T>>> : std::true_type {};

template<typename T>
using simple_func_t = decltype(std::declval<T>().SimpleFunc());

template<typename T>
using has_simple_func = detect<T, simple_func_t>;

class Test
{
public:
    int SimpleFunc()
    {
        cout << "SimpleFunc\n";
        return 0;
    }
};

void Foo()
{
    if constexpr (has_simple_func<Test>())
    {
        Test test;
        test.SimpleFunc();
    }
}

The problem is that I can not make it work for specialized member functions. I have tried that:

template<typename, template<typename> class, typename = void_t<>>
struct detect_ver : std::false_type {};

template<typename T, template<typename> class Op>
struct detect_ver<T, Op, void_t<Op<T>>> : std::true_type {};

template<typename T, int version>
using template_func_t = decltype(std::declval<T>().TemplateFunc<version>());

template<typename T, int version>
using has_template_func = detect_ver<T, template_func_t<T, version>>;

class Test
{
public:
    template<int version>
    int TemplateFunc();

    template<>
    int TemplateFunc<1>()
    {
        cout << "TemplateFunc1\n";
        return 1;
    }
};

void Foo()
{
    if constexpr (has_template_func<Test, 1>())
    {
        Test test;
        test.TemplateFunc<1>();
    }
}

But I keep getting strange compile errors like this: error C2760: syntax error: unexpected token ')', expected 'expression' for line: using template_func_t = decltype(std::declval<T>().TemplateFunc<version>());

UPDATE: I have tried solution provided by jarod. It compiles, but detect_ver deducted as false_type. I do use MSVC.

Fozek
  • 11
  • 4

2 Answers2

1

You have to change your traits to match detect_ver parameters:

template<int version>
struct template_func_t
{
    template<typename T>
    using type = decltype(std::declval<T>().template TemplateFunc<version>());
};

template<typename T, int version>
using has_template_func = detect_ver<T, template_func_t<version>::template type>;

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

Unfortunately, although @Jarod's answer solves the syntax errors, this still doesn't work, because if constexpr (has_template_func<Test, N>()) always returns true, regardless of the value of N.

To see why this is so, consider the following simplified code:

class Test
{
public:
    template<int version>
    int TemplateFunc();
};

int main ()
{
    Test test;
    test.TemplateFunc<1>();
}

This compiles but does not link (undefined reference to int Test::TemplateFunc<1>()).

This is because this:

template<int version>
int TemplateFunc();

acts as a forward declaration of TemplateFunc (in fact, it is a forward declaration of TemplateFunc), and that is enough to compile the code.

So, tl;dr, there's no way to check for the existence of a particular template specialisation, period.

OP: I'm not sure why you're always getting std::false_type. That's not what I see with gcc or clang.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48