I have a problem with MSVC 2017 & 2019 about this limitation: I would like to know at compile time if a certain CRTP template "derived" class have a specific function.
I got this as my class trait evaluation :
template <typename T>
class function_exists_trait
{
private:
template <typename U>
static auto test_todo(U * u) -> decltype(&U::exists) {}
static auto test_todo(...) -> std::false_type {}
public:
static constexpr bool value{ !std::is_same<decltype(test_todo(static_cast<T*>(nullptr))), std::false_type>::value };
};
I tested it with some trivial classes :
struct t1 { void exists() {} };
struct t2 { void exists() {} };
struct t3 {};
struct t4 : public t1 {};
struct t5 : public t3 {};
struct t6 : public t3 { void exists() {} };
I got the expected results. As expected, the evaluations give : 1 1 0 1 0 1 with this test : cout << function_exists_trait<t1>::value << " " << ...
I got the expected results for the following CRTP simple implementations (0 1 1 1) :
template <typename t> struct u1 {};
struct crtp1 : public u1<crtp1> { void exists() {} };
template <typename t> struct u2 { void exists() {} };
struct crtp2 : public u2<crtp2> {};
cout << function_exists_trait<u1<int>>::value << " "
<< function_exists_trait<crtp1>::value << " "
<< function_exists_trait<u2<int>>::value << " "
<< function_exists_trait<crtp2>::value << endl;
The problem is this : when a try to evaluate the trait inside the CRTP base class, nothing is working and I do not understand why.
template <typename t> struct u3 {
static inline constexpr bool value{ function_exists_trait<t>::value };
};
struct crtp3 : public u3<crtp3> { void exists() {} };
template <typename t> struct u4 {
void exists() {}
static inline constexpr bool value{ function_exists_trait<t>::value };
};
struct crtp4 : public u4<crtp4> {};
template <typename t> struct u5 {
void exists() {}
static inline constexpr bool value{ function_exists_trait<t>::value };
};
struct crtp5 : public u5<crtp5> {
void exists() {}
};
The following code give this result : 0 0 - 0 0 - 0 0 - 0 0
cout << function_exists_trait<u3<int>>::value << " " << u3<int>::value << " - "
<< function_exists_trait<crtp3>::value << " " << crtp3::value << " - "
<< function_exists_trait<crtp4>::value << " " << crtp4::value << " - "
<< function_exists_trait<crtp5>::value << " " << crtp5::value << endl;
I have posted this problem thinking I was doing something wrong but it seem to be a problem with MSVC. Thanks to P.W. who showed me that it seem to be a limitation of MSVC. He showed me that exact same code give this result under gcc : 0 0 - 1 1 - 1 1 - 1 1
Do anybody have any suggestion how to solve this. Maybe there is an obvious solution with MSVC to trigger the expected result. Or simply another way to achieve the same goal under MSVC.