我试图做一些有趣的事情,并在VC++ 2015打破了。我在clang和g++中尝试了它,没有编译或运行时错误。 (链接到rextester.com演示)
#include <type_traits>
#include <iostream>
int fn1() { return 1; }
int fn2(int) { return 2; }
template <typename FN_T, FN_T FN, typename DERIVED>
class test_base
{
template <typename T = DERIVED, typename = std::enable_if_t<!T::fn_specified>>
int fn()
{
return FN();
}
public:
int fn_indirect()
{
return static_cast<DERIVED*>(this)->fn();
}
};
template <typename FN_T, FN_T FN, typename ENABLER = void>
class test_derived : public test_base<FN_T, FN, test_derived<FN_T, FN>>
{
public:
static constexpr bool fn_specified = false;
};
template <typename FN_T, FN_T FN>
class test_derived<FN_T, FN, std::enable_if_t<FN == &fn2>>
: public test_base<FN_T, FN, test_derived<FN_T, FN>>
{
using base = test_base<FN_T, FN, test_derived<FN_T, FN>>;
friend base;
public:
static constexpr bool fn_specified = true;
int fn()
{
return FN(1);
}
};
int main(void)
{
test_derived<decltype(&fn1), &fn1> x1;
test_derived<decltype(&fn2), &fn2> x2;
std::cout << x1.fn_indirect() << " ";
// comment next line out and it'll work in VC++
std::cout << x2.fn_indirect() << std::endl;
return 0;
}
我的想法是,如果我在派生类中指定fn()
,那么基类将不会实例化该函数,因此在调用FN()
时由于参数太多而不会导致错误,FN()
指向特定函数(在这种情况下为fn2(int)
)。
我这样做是正确的,还是我错过了什么?
答案 0 :(得分:0)
您正在使用的构造称为表达式SFINAE。 Visual Studio直到2017年才向support it声明。 Visual Studio 2015的更新支持部分支持(详细了解update 1,updates 1, 2 and 3)。然而,要使其在所有版本的MSVC中都能工作,需要创建不涉及表达式的变通方法,例如:里面的模板专业化参数。要在你的情况下实现它,可以使用模式匹配和附加的间接层(例如std :: integral_constant):
#include <type_traits>
#include <iostream>
int fn1() { return 1; }
int fn2(int) { return 2; }
template <typename FN_T, FN_T FN, typename DERIVED>
class test_base
{
template <typename T = DERIVED, typename = std::enable_if_t<!T::fn_specified>>
int fn()
{
return FN();
}
public:
int fn_indirect()
{
return static_cast<DERIVED*>(this)->fn();
}
};
template <class FN_T>
class test_derived : public test_base<typename FN_T::value_type, FN_T::value, test_derived<FN_T>>
{
public:
static constexpr bool fn_specified = false;
};
template <typename FN_T>
class test_derived<std::integral_constant<FN_T, &fn2>>
: public test_base<FN_T, &fn2, test_derived<std::integral_constant<FN_T, &fn2>>>
{
using base = test_base<FN_T, &fn2, test_derived<std::integral_constant<FN_T, &fn2>>>;
friend base;
public:
static constexpr bool fn_specified = true;
int fn()
{
return fn2(1);
}
};
int main(void)
{
test_derived<std::integral_constant<decltype(&fn1), &fn1>> x1;
test_derived<std::integral_constant<decltype(&fn2), &fn2>> x2;
std::cout << x1.fn_indirect() << " ";
// comment next line out and it will work
std::cout << x2.fn_indirect() << std::endl;
return 0;
}