在尝试使用 SFINAE 禁用功能时,我是否创建了未定义的行为?
While trying to use SFINAE to disable functions, have I created undefined behavior?
我正在尝试使用 SFINAE 根据一些非模板枚举参数禁用 class 的某些功能。
以下代码不能使用 gcc 编译,但在使用 msvc 编译器时似乎可以按预期编译和工作。
#include <iostream>
#include <type_traits>
enum class B { VARIANT1, VARIANT2 };
template<B B_VAL>
struct A {
template<class = std::enable_if_t<B_VAL == B::VARIANT1>>
void func1() {
std::cout<<"VARIANT1"<<std::endl;
}
template<class = std::enable_if_t<B_VAL == B::VARIANT2>>
void func2() {
std::cout<<"VARIANT2"<<std::endl;
}
};
int main()
{
A<B::VARIANT1> a;
a.func1();
}
预期的(和 msvcs)行为是调用 enable_if_t 条件等于 false 的函数会导致编译时错误,或者如果存在重载函数,则会删除用于重载解析的候选函数在这个例子中。在所有其他情况下,代码应该可以正常编译。
另一方面,gcc 告诉我它在 func2 模板中的 enable_if_t 的“struct std::enable_if”中找不到名为“type”的类型,这非常有意义,因为名为“type”的成员仅在条件等于 true 时出现在 enable_if 中。但这不应该是 SFINAE 功能所需的行为吗?编译器不应该忽略 func2,因为它从未被调用过吗?
我现在有三个问题:
由于两个编译器产生不同的行为,是否未定义,如果是,parts/statements?
SFINAE 是否适合实现我的目标,还是我误解了它的用例?
使用静态断言作为替代方案会更好吗?
如果这个问题与 重复,我很抱歉,但我认为那里的答案对我的问题没有太大帮助。
GCC 是对的。这是因为您没有将 SFINAE 用于您的功能。看起来你这样做是因为你使用了标准库中的 SFINAE 实用程序,但这里缺少一个关键成分。
“SFINAE”中的'S'代表替换。将模板参数替换为我们尝试实例化的模板的参数。现在,有问题的模板是 func2
。为了使 SFINAE 工作,func2
的参数必须不能被其参数替换。但是这里
std::enable_if_t<B_VAL == B::VARIANT2>
func2
参数没有被使用。它不依赖于替换为 func2
期间发生的任何事情。它只是一个无效类型,完全独立于实际实例化 func2
.
的尝试
虽然不难修复
template<B B_VAL_ = B_VAL, class = std::enable_if_t<B_VAL_ == B::VARIANT1>>
void func1() {
std::cout<<"VARIANT1"<<std::endl;
}
template<B B_VAL_ = B_VAL, class = std::enable_if_t<B_VAL_ == B::VARIANT2>>
void func2() {
std::cout<<"VARIANT2"<<std::endl;
}
现在,检查是针对正确模板的替换。
我正在尝试使用 SFINAE 根据一些非模板枚举参数禁用 class 的某些功能。
以下代码不能使用 gcc 编译,但在使用 msvc 编译器时似乎可以按预期编译和工作。
#include <iostream>
#include <type_traits>
enum class B { VARIANT1, VARIANT2 };
template<B B_VAL>
struct A {
template<class = std::enable_if_t<B_VAL == B::VARIANT1>>
void func1() {
std::cout<<"VARIANT1"<<std::endl;
}
template<class = std::enable_if_t<B_VAL == B::VARIANT2>>
void func2() {
std::cout<<"VARIANT2"<<std::endl;
}
};
int main()
{
A<B::VARIANT1> a;
a.func1();
}
预期的(和 msvcs)行为是调用 enable_if_t 条件等于 false 的函数会导致编译时错误,或者如果存在重载函数,则会删除用于重载解析的候选函数在这个例子中。在所有其他情况下,代码应该可以正常编译。
另一方面,gcc 告诉我它在 func2 模板中的 enable_if_t 的“struct std::enable_if
我现在有三个问题:
由于两个编译器产生不同的行为,是否未定义,如果是,parts/statements?
SFINAE 是否适合实现我的目标,还是我误解了它的用例?
使用静态断言作为替代方案会更好吗?
如果这个问题与
GCC 是对的。这是因为您没有将 SFINAE 用于您的功能。看起来你这样做是因为你使用了标准库中的 SFINAE 实用程序,但这里缺少一个关键成分。
“SFINAE”中的'S'代表替换。将模板参数替换为我们尝试实例化的模板的参数。现在,有问题的模板是 func2
。为了使 SFINAE 工作,func2
的参数必须不能被其参数替换。但是这里
std::enable_if_t<B_VAL == B::VARIANT2>
func2
参数没有被使用。它不依赖于替换为 func2
期间发生的任何事情。它只是一个无效类型,完全独立于实际实例化 func2
.
虽然不难修复
template<B B_VAL_ = B_VAL, class = std::enable_if_t<B_VAL_ == B::VARIANT1>>
void func1() {
std::cout<<"VARIANT1"<<std::endl;
}
template<B B_VAL_ = B_VAL, class = std::enable_if_t<B_VAL_ == B::VARIANT2>>
void func2() {
std::cout<<"VARIANT2"<<std::endl;
}
现在,检查是针对正确模板的替换。