简体   繁体   English

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

[英]SFINAE without void_t (maybe a template specialization question)

Sorry for the title, I am not sure about the category of my question.对不起标题,我不确定我的问题的类别。 I am trying to do an is_incrementable with SFINAE.我正在尝试用 SFINAE 做一个 is_incrementable。 This works fine, however when I try to understand it more deeply, and when I remove the void_t then the code snippet does not work as expected.这很好用,但是当我尝试更深入地理解它时,并且当我删除 void_t 时,代码片段无法按预期工作。

The original code:原代码:

#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 evaluates to is_incrementable<int, void>::value which is the original template class and the specialization, too. i) is_incrementable<int>::value的计算结果为is_incrementable<int, void>::value ,它也是原始模板 class 和特化。 In this case the compiler choses the specialized version, so value eguals to 1. For the string version, the specialization fails, SFINAE kicks in, so we have the base template only.在这种情况下,编译器选择了专门的版本,所以将 eguals 的值设为 1。对于字符串版本,专门化失败,SFINAE 开始,所以我们只有基本模板。 (value equals to 0) (值等于 0)

ii) When I change the code, and remove the void_t 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 and 0 is printed.打印 0 和 0。 is_incrementable<int>::value means is_incrementable<int, void>::value , the specialization is is_incrementable<int, int>::value (I think), so we use the basic template. is_incrementable<int>::value表示is_incrementable<int, void>::value ,特化是is_incrementable<int, int>::value (我认为),所以我们使用基本模板。 For the string the specialization fails anyway.对于字符串,专业化无论如何都会失败。

My question: iii) The funny part.我的问题:iii)有趣的部分。 If now I change the first line to use int as the default type如果现在我将第一行更改为使用 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;
}

then again 0 and 0 are printed.然后再次打印 0 和 0。 Why?为什么? is_incrementable<int>::value means (I think) is_incrementable<int, int>::value and decltype( ++std::declval<T&>() ) should be int as well. is_incrementable<int>::value意味着(我认为) is_incrementable<int, int>::valuedecltype( ++std::declval<T&>() )也应该是 int 。 So I think the compiler should use the specialized version.所以我认为编译器应该使用专门的版本。 (and 1 should be printed) (并且应该打印 1)

If I remove decltype( ++std::declval<T&>() ) and write int then 1 and 1 printed (which are the expected print outs).如果我删除decltype( ++std::declval<T&>() )并写入int然后打印 1 和 1 (这是预期的打印输出)。

Could someone explain me what is happening in iii) please.有人可以解释一下 iii) 中发生的事情吗?

When T is int , decltype( ++std::declval<T&>() ) is int & , not int .Tint时, decltype( ++std::declval<T&>() )int & ,而不是int So to get the output you were expecting, you would either change this:因此,要获得您期望的 output,您可以更改此:

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

to this:对此:

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

or else change this:或者改变这个:

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

to this:对此:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM