为什么编译器在使用检测习惯用语时不提示双重定义?
Why doesn't compiler prompt double definition when using detection idiom?
让我们做一些具体的事情:
#include <utility>
#include <vector>
template <typename ... Ts>
using void_t = void;
template <typename T, typename = void_t<>>
struct is_lt_comparable : std::false_type {};
template <typename T>
struct is_lt_comparable<T, void_t<decltype(std::declval<T>() < std::declval<T>())>> : std::true_type {};
template <typename T>
static constexpr bool is_lt_comparable_v = is_lt_comparable<T>::value;
struct test{};
int main()
{
#define error_message "detection doesn't work correctly"
static_assert(is_lt_comparable_v<int>, error_message);
static_assert(!is_lt_comparable_v<test>, error_message);
static_assert(is_lt_comparable_v<std::vector<int>>, error_message);
}
魔杖盒。
在上面的代码中,为什么第一个和最后一个断言不触发is_lt_comparable
的双重定义?
void_t
任何论点仍然是void
.因此,模板的最后一个未命名参数始终是void
。IIRC类型别名不被视为不同的类型,因此我的直觉使我相信我错过了一些东西。
具体来说,假设两个声明都有效,并且结果是相同的类型,例如在第一个声明中,is_lt_comparable<int, void>
,它如何知道要实例化哪个模板?
你写道:is_lt_comparable<int>
.这就是发生的事情。
-
选择主模板,并推断第二个模板参数,因为它是默认值。所以,你实际上有
is_lt_comparable<int, void>
. -
现在考虑模板专用化,以查看是否存在匹配项。
它 找到第一个(也是唯一一个)专用化,并且因为它是部分专用化,而不是完整的专用化,所以它基本上也需要实例化它。所以你得到:
is_lt_comparable<int, void_t<decltype(std::declval<int>() < std::declval<int>())>>
现在,如果
<
表达式格式不正确,则不考虑专用化,编译器将回退到主模板。但如果它是有效的,那么部分专业化就变成了:
is_lt_comparable<int, void>
.这与我们在 1) 中实例化的模板完全匹配,因此编译器选择了该模板。从形式上讲,这称为部分排序规则。
如果您仍然感到困惑,请考虑以下情况:
template<typename> void foo() {}
template<> void foo<int>() {}
如果我这样做foo<int>()
,也不会有双重定义错误,就像你说的那样。专用化比主模板更匹配,因此编译器甚至不会使用T = int
实例化主模板(它不能)。
static_assert
是一个声明,不定义任何实体。请参阅有关定义和 ODR 的 cppreference 文章。代码中只有模板实例化,没有定义。
在上面的代码中,为什么第一个和最后一个断言不触发is_lt_comparable的双重定义?
is_lt_comparable
不是一种类型。它是模板的名称。
is_lt_comparable_v<int>
导致is_lt_comparable<int, void>
的展开,这是一种类型。
is_lt_comparable_v<test>
导致is_lt_comparable<test, void>
的扩展,这是一种不同的类型。
再一次,is_lt_comparable<std::vector<int>, void>
是另一种独特的类型。
- 在提升multi_index容器中,是否定义了"default index"?
- #定义c-预处理器常量..我做错了什么
- 用C++中的一个变量定义一个常量
- 部分定义/别名模板模板参数
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- #为""定义宏;静态";针对不同的上下文
- 如何确保C++函数在定义之前声明(如override关键字)
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在命名空间中定义函数还是限定函数
- 此代码是否违反一个定义规则
- 编译C++时未定义的引用
- 不同翻译单元中不可重载的非内联函数定义
- 为什么在定义函数之前先声明它
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 使用用户定义函数的字符串反转
- 用户定义函数中的指针和输入
- "提示"使用未定义的结构 - winSock
- 为什么编译器在使用检测习惯用语时不提示双重定义?