使用检测成语时,为什么编译器不会提示双重定义?

时间:2018-01-01 16:41:02

标签: c++ c++14 template-meta-programming void-t

让我们采取具体的措施:

#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);

}

Wandbox

在上面的代码中,为什么不首先和最后一个断言触发is_lt_comparable的双重定义?

带有任何参数的

void_t仍为void。因此,模板的最后一个未命名参数始终为void。 IIRC类型的别名不被认为是不同的类型,因此我的直觉使我相信我错过了某些东西。

具体,如果选择两个声明都有效,并产生相同的类型,例如在第一个is_lt_comparable<int, void>中,它如何知道要实例化哪个模板?

3 个答案:

答案 0 :(得分:4)

你写道:is_lt_comparable<int>。这就是发生的事情。

  1. 选择主模板,推断出第二个模板参数,因为它是默认值。所以,你实际上有is_lt_comparable<int, void>

  2. 现在考虑模板专精,看看是否匹配。

  3. 它找到了第一个(也是唯一的)特化,因为它是一个部分特化,而不是一个完整的,它基本上也需要实例化它。所以你得到:

    is_lt_comparable<int, void_t<decltype(std::declval<int>() < std::declval<int>())>>
    

    现在,如果<表达式格式不正确,则不考虑特化,编译器会回退到主模板。

  4. 但如果它有效,则部分特化将变为:is_lt_comparable<int, void>。这与我们在1)中实例化的模板完全匹配,因此编译器会选择那个。形式上,这被称为部分排序规则。

  5. 如果您仍然感到困惑,请考虑以下事项:

    template<typename> void foo() {}
    template<> void foo<int>() {}
    

    如果我foo<int>(),那么也不会出现双重定义错误,就像你说的那样。专门化是比主要的更好匹配,因此编译器甚至不使用T = int实例化主模板(它不能)。

答案 1 :(得分:1)

static_assert声明,并未定义任何实体。见cpprefrence article on Definitions and ODR。代码中只有模板实例化,但没有定义。

答案 2 :(得分:0)

  

在上面的代码中,为什么不首先和最后一个断言触发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>是另一种截然不同的类型。