为什么没有选择模板专业化?

Why is the template specialization not chosen?

本文关键字:专业化 有选择 为什么      更新时间:2023-10-16

我写了以下代码:

#include <iostream>
#include <string>
#include <type_traits>
template<typename, typename = void>
struct is_incrementable : std::false_type {};
template<typename T>
struct is_incrementable<T, decltype( ++std::declval<T&>() )> : std::true_type {};
int main()
{
    std::cout << is_incrementable<std::string>::value << std::endl;
    std::cout << is_incrementable<int>::value << std::endl;
}

当我运行它时,我得到0 0.但我期待0 1.

有什么想法吗?

对于std::string,选择主要模板并考虑专业化。但是decltype(++std::declval<T&>())格式不正确,因此不考虑它并使用主模板(非专用模板(,从而导致0

如果你使用int,它会变得有点复杂。与往常一样,编译器选择主模板,然后考虑专用化(这是因为专用化始终被认为是更好的匹配(。专用化对于int <int, int&>,但它与非专用模板<int, void>不匹配(void是默认模板参数(,因此会忽略专用化,因为它不匹配。

因此,默认模板参数的类型必须匹配,否则不考虑专用化,因为仅当每个模板参数都与专用化匹配时才采用专用化。

只需在末尾附加一个void()即可使专用化与第二个模板参数匹配,因为左侧表达式将被丢弃,void()的类型为 void ,这与主模板的第二个模板参数匹配。

template<typename T>
struct is_incrementable<T, decltype( ++std::declval<T&>(), void() )> : std::true_type {};

在 C++17 中,您将为此使用 std::void_t