【发布时间】:2023-04-05 16:31:01
【问题描述】:
基本问题陈述
我正在学习 SFINAE。我尝试了一个极其简单的enable_if:
// 1: A foo() that accepts arguments that are derived from Base
template <typename T, typename Enable = enable_if_t<std::is_base_of_v<Base, T>>>
void foo(T thing) {
std::cout << "It's a derived!" << std::endl;
}
// 2: A foo() that accepts all other arguments
template <typename T, typename Enable = enable_if_t<!std::is_base_of_v<Base, T>>>
void foo(T thing) {
std::cout << "It's not a derived." << std::endl;
}
编译器抱怨foo 是多重定义的。互联网告诉我这是因为在检查函数签名时模板参数不相关。
我尝试过的变体
在我尽可能地进行最基本的元编程的过程中,我开始在问题上抛出语法。以下是我为 enable_if 语句尝试过的事情的列表(反转语句,即 !std::is_base_of 相同,但为简洁起见省略):
匿名类型,无typename,等于0
https://en.cppreference.com/w/cpp/types/enable_if 告诉我我在上面所做的事情是错误的。但它的建议(在第一个注释块下找到)相当隐秘,更重要的是,它也无法编译。
std::enable_if_t<std::is_base_of_v<Base, T>> = 0
匿名类型,无typename,等于void
考虑到如果我正在使用类型进行编程,使用类型将是一个明智的选择,因此我尝试将模板默认为void。没有骰子。
std::enable_if_t<std::is_base_of_v<Base, T>> = void
匿名类型,是typename,等于void
当我们向它抛出语法时,如果我将此模板参数默认为一个类型,我不应该使用 typename 关键字吗?
typename std::enable_if_t<std::is_base_of_v<Base, T>> = void
最终的结果,哦,显然是这样的
typename enable_if_t<std::is_base_of_v<Base, T>, T>* = nullptr
我已经问过我认识的每个人为什么这有效,而我的其他变体却没有,他们同样感到困惑。我不知所措。更令人困惑的是,如果我将这种类型命名为(例如typename Enable = ...),它将无法编译。
如果有更熟悉 TMP 和 enable_if 的人向我解释一下,我将不胜感激:
- 为什么将
enable_if声明为指向类型的指针并将其默认为nullptr有效? - 默认
enable_if的语义规则是什么? -
enable_if产生的命名类型的语义规则是什么? - 有没有我可以使用的参考来清楚地解释这个和其他类似的规则在模板领域?
非常感谢。
【问题讨论】:
-
void不是=左侧的非类型模板参数的有效值“如果我命名此类型” - 它不是类型,typename enable_if_t<std::is_base_of_v<Base, T>, T>*将是一个指向T值的指针,它需要一个有效的指针值作为初始值设定项,而不是某种类型 -
cppreference 上的示例确实可以编译。您在将其放入代码时更改了它,方法是选择不具有 0 作为有效初始化程序的类型。
标签: c++ templates c++17 enable-if