如何使用 SFINAE 在方法调用中有条件地定义变量?



我想定义一个提供公共method()的模板类IEmethod()调用底层私有run(),可以接受传递给IE的模板参数相关的参数。所以:

  • 对于IE<void>,执行不带参数的run()
  • 对于IE<T>中的任何其他 T,run(vector<T>)被执行。

我想我正确地 SFINAE 方法run(),但我在定义应该传递给run的参数时遇到问题。我想出了以呈现的方式定义Extra,但我得到了无法推断 T 的错误。

编辑:我需要一个最多适用于C++14的解决方案。

template<typename X=void>
class IE
{
template<typename T=void>
struct Extra;
template<typename T>
struct Extra<enable_if_t<is_void<T>::value, T>> {};
template<typename T>
struct Extra<enable_if_t<!is_void<T>::value, T>>
{
std::vector<T> ex;
};
template<typename X_=X>
void run(enable_if_t<is_void<X_>::value , Extra<X_>> x) {
cout << "In run" << endl;
}
template<typename X_ = X>
void run(enable_if_t<!is_void<X_>::value , Extra<X_>> x)
{
cout << "In run: X=" << x.ex.size() << endl;
}
public:
void method()
{
Extra<X> x;
run(x);
}
};
int main() {
IE<double> ie1;
ie1.method(); // should execute run(vector<double>)
IE<> ie2;
ie2.method(); // should execute run()
return 0;
}

从你的意图来看,你可以用Constexpr来做(从C++17开始(。

template<typename X=void>
class IE
{
void run() {
cout << "In run()" << endl;
}
void run(std::vector<X> x)
{
cout << "In run: X=" << x.size() << endl;
}
public:
template<typename X_ = X>
void method()
{
if constexpr (std::is_same_v<X_, void>)
run();
else
run(std::vector<X_>{...});
}
};

在C++17之前,您可以申请SFINAE(或专业化(,例如

template<typename X=void>
class IE
{
void run() {
cout << "In run()" << endl;
}
void run(std::vector<X> x)
{
cout << "In run: X=" << x.size() << endl;
}
public:
template<typename X_ = X>
std::enable_if_t<std::is_same<X_, void>::value> method()
{
run();
}
template<typename X_ = X>
std::enable_if_t<!std::is_same<X_, void>::value> method()
{
run(std::vector<X_>{...});
}
};

对于您的原始解决方案,您应该将 SFINAE 应用

template<typename X=void>
class IE
{
template<typename T, typename = void>
struct Extra;
template<typename T>
struct Extra<T, enable_if_t<is_void<T>::value>> {};
template<typename T>
struct Extra<T, enable_if_t<!is_void<T>::value>>
{
std::vector<T> ex;
};
template<typename X_ = X>
enable_if_t<is_void<X_>::value> run(Extra<X_> x) {
cout << "In run" << endl;
}
template<typename X_ = X>
enable_if_t<!is_void<X_>::value> run(Extra<X_> x)
{
cout << "In run: X=" << x.ex.size() << endl;
}
public:
void method()
{
Extra<X> x;
run(x);
}
};

这是你对Extra的定义是不正确的,

您可以简单地将其移出类外并使用常规专业化:

template<typename T>
struct Extra
{
std::vector<T> ex;
};
template<>
struct Extra<void> {};

演示

可能是实际代码更复杂,但对于问题中提出的代码,为IE<void>提供专用化是最简单的方法。摆脱所有这些enable_if的东西,并在定义IE之后添加专业化:

template <>
class IE<void> {
void run() { /* ... */ }
public:
void method() { run(); }
};

(是的,我不喜欢使用constexpr if来编写具有两个或多个完全独立执行路径的函数,具体取决于某些类型的演算;这太像#ifdef ... #elif ... #endif了(

最新更新