std::enable_if_t不匹配部分特化

huangapple go评论63阅读模式
英文:

std::enable_if_t doesn't match partial specialization

问题

如果我理解正确,别名模板实际上是模板,因此可以作为参数传递到期望类模板的地方。这就是以下代码有效的原因 -

template <template <bool, typename> T>
struct foo {};

foo<std::enable_if_t> x;

也可以使用部分特化来匹配模板类。这就是为什么以下代码会输出"Version 2"的原因。

template <typename T>
struct foo {
    static void print() {std::cout << "Version 1" << std::endl;}
};

template <template <typename> typename T, typename X>
struct foo<T<X>> {
    static void print() {std::cout << "Version 2" << std::endl;}
};

template <typename T>
struct bar {

};

foo<bar<int>>::print();

现在我的问题是,为什么以下代码不输出"Version 2",而是输出"Version 1"?

template <typename T>
struct foo {
	static void print() {std::cout << "Version 1" << std::endl;}	
};

template <template <bool, typename> typename T, bool X, typename Y>
struct foo<T<X, Y>> {
	static void print() {std::cout << "Version 2" << std::endl;}
};

foo<std::enable_if_t<true, int>>::print();

第二个部分特化不应该更匹配,其中T=std::enable_if_t,X=true,Y=int吗?

英文:

If my understanding is correct, alias templates are actually templates and hence can be passed as arguments where a class template is expected. Which is what makes the following code valid -

template &lt;template &lt;bool, typename&gt; T&gt;
struct foo {};

foo&lt;std::enable_if_t&gt; x;

It is also possible to use partial specialization to match template classes. Which is why the following code prints "Version 2".

template &lt;typename T&gt;
struct foo {
    static void print() {std::cout &lt;&lt; &quot;Version 1&quot; &lt;&lt; std::endl;}
};

template &lt;template &lt;typename&gt; typename T, typename X&gt;
struct foo&lt;T&lt;X&gt;&gt; {
    static void print() {std::cout &lt;&lt; &quot;Version 2&quot; &lt;&lt; std::endl;}
};

template &lt;typename T&gt;
struct bar {

};
...
foo&lt;bar&lt;int&gt;&gt;::print();

Now my question is, why doesn't the following code print "Version 2", but instead prints "Version 1"

template &lt;typename T&gt;
struct foo {
	static void print() {std::cout &lt;&lt; &quot;Version 1&quot; &lt;&lt; std::endl;}	
};


template &lt;template &lt;bool, typename&gt; typename T, bool X, typename Y&gt;
struct foo&lt;T&lt;X, Y&gt;&gt; {
	static void print() {std::cout &lt;&lt; &quot;Version 2&quot; &lt;&lt; std::endl;}
};

foo&lt;std::enable_if_t&lt;true, int&gt;&gt;::print();

Shouldn't the second partial specialization be a better match where T=std::enable_if_t, X=true, Y=int?

答案1

得分: 3

以下是已翻译的内容:

预期的结果是,以下内容会打印 "Version 2":

foo<std::enable_if<true, int>>::print();

然而在你的示例中,类型 std::enable_if_t<true, int> 等同于 int,无法匹配 T<X, Y>

cppreference 对此解释如下:

别名模板是一种模板,当进行特化时,等同于将别名模板的模板参数替换为 type-id 中的模板参数的结果。

别名 std::enable_if_t 可以匹配 template <bool, typename> typename,但一旦特化,就无法拆解。

英文:

As expected, the following prints "Version 2"

foo&lt;std::enable_if&lt;true, int&gt;&gt;::print();

In your example however, the type std::enable_if_t&lt;true, int&gt; is equivalent to int and cannot match cannot match T&lt;X, Y&gt;.

cppreference explains it like this:

> An alias template is a template which, when specialized, is equivalent to the result of substituting the template arguments of the alias template for the template parameters in the type-id

The alias std::enable_if_t can match template &lt;bool, typename&gt; typename, but once specialized it cannot be deconstructed.

答案2

得分: 1

每当别名模板具有参数时,它会立即被替换为它所别名的类型。所以,例如,std::enable_if_t&lt;true, int&gt; 会立即被替换为 int。这甚至适用于依赖上下文;所以,例如,如果你有一个这样的函数:

template &lt;bool b, typename T&gt;
void foo(std::enable_if_t&lt;b, T&gt;);

编译器会将其重写为:

template &lt;bool b, typename T&gt;
void foo(typename std::enable_if&lt;b, T&gt;::type);

原始的别名已经从等式中消失。

因此,像 T&lt;X, Y&gt; 这样的类型不能用来推断 T 作为别名模板,因为无论为 T&lt;X, Y&gt; 提供了什么类型 U 以匹配,如果它最初具有某个别名模板 A 的形式 A&lt;X, Y&gt;,它将被替换为该别名模板所别名的内容,而 A 将不再存在。(但是,别名模板可以被推断为类模板的参数,该类模板具有模板模板参数,因为别名模板可以作为有效的模板模板参数)。

英文:

Whenever an alias template has arguments, it is immediately replaced with the type it aliases. So, for example, std::enable_if_t&lt;true, int&gt; is immediately replaced by int. This applies even in a dependent context; so for example if you have a function like this:

template &lt;bool b, typename T&gt;
void foo(std::enable_if_t&lt;b, T&gt;);

the compiler rewrites it to:

template &lt;bool b, typename T&gt;
void foo(typename std::enable_if&lt;b, T&gt;::type);

The original alias has disappeared from the equation.

It follows that a type like T&lt;X, Y&gt; can't be used to deduce T as an alias template because whatever type U is provided for T&lt;X, Y&gt; to match against, if it originally had the form A&lt;X, Y&gt; for some alias template A, it would have been replaced by whatever that alias template aliases to, and A would no longer be present. (However, an alias template can be deduced as an argument of a class template that has a template template parameter, since an alias template can be a valid template template argument)

huangapple
  • 本文由 发表于 2023年2月16日 11:06:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/75467451.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定