没有 void_t 的 SFINAE(可能是模板专业化问题)

SFINAE without void_t (maybe a template specialization question)

对不起标题,我不确定我问题的类别。 我正在尝试使用 SFINAE 进行 is_incrementable。这工作正常,但是当我尝试更深入地理解它时,当我删除 void_t 时,代码片段无法按预期工作。

原代码:

#include <iostream>

template< typename, typename = void >
struct is_incrementable : std::false_type { };

template< typename T >
struct is_incrementable<T,
          std::void_t<decltype( ++std::declval<T&>() )>

       > : std::true_type { };

int main()
{
    std::cout << is_incrementable<int>::value << std::endl;  // prints 1
    std::cout << is_incrementable<std::string>::value << std::endl;  // prints 0
    return 0;
}

i) is_incrementable<int>::value 评估为 is_incrementable<int, void>::value,这是原始模板 class 和专业化。在这种情况下,编译器选择专用版本,因此值等于 1。 对于字符串版本,专业化失败,SFINAE 启动,所以我们只有基本模板。 (值等于 0)

ii) 当我更改代码并删除 void_t

template< typename, typename = void > 
struct is_incrementable : std::false_type { };

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

int main()
{
    std::cout << is_incrementable<int>::value << std::endl;  // prints 0
    std::cout << is_incrementable<std::string>::value << std::endl;  // prints 0
    return 0;
}

0 并打印 0。 is_incrementable<int>::value表示is_incrementable<int, void>::value,特化为 is_incrementable<int, int>::value(我认为),所以我们使用基本模板。对于字符串,专业化无论如何都会失败。

我的问题: 三) 有趣的部分。 如果现在我将第一行更改为使用 int 作为默认类型

#include <iostream>

template< typename, typename = int >  // !!! int is used now
struct is_incrementable : std::false_type { };

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

int main()
{
    std::cout << is_incrementable<int>::value << std::endl;  // prints 0
    std::cout << is_incrementable<std::string>::value << std::endl;  // prints 0
    return 0;
}

然后再次打印 0 和 0。 为什么? is_incrementable<int>::value 表示(我认为)is_incrementable<int, int>::valuedecltype( ++std::declval<T&>() ) 也应该是 int。 所以我认为编译器应该使用专门的版本。 (应该打印 1)

如果我删除 decltype( ++std::declval<T&>() ) 并写入 int 然后打印 1 和 1(这是预期的打印输出)。

有人可以向我解释一下 iii) 中发生了什么吗。

Tint时,decltype( ++std::declval<T&>() )int &,而不是int。因此,要获得您期望的输出,您可以更改此设置:

template< typename, typename = int >
struct is_incrementable : std::false_type { };

对此:

template< typename, typename = int & >
struct is_incrementable : std::false_type { };

或者改变这个:

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

对此:

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