英文:
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 <template <bool, typename> T>
struct foo {};
foo<std::enable_if_t> x;
It is also possible to use partial specialization to match template classes. Which is why the following code prints "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();
Now my question is, why doesn't the following code print "Version 2", but instead prints "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();
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<std::enable_if<true, int>>::print();
In your example however, the type std::enable_if_t<true, int>
is equivalent to int
and cannot match cannot match T<X, Y>
.
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 <bool, typename> typename
, but once specialized it cannot be deconstructed.
答案2
得分: 1
每当别名模板具有参数时,它会立即被替换为它所别名的类型。所以,例如,std::enable_if_t<true, int>
会立即被替换为 int
。这甚至适用于依赖上下文;所以,例如,如果你有一个这样的函数:
template <bool b, typename T>
void foo(std::enable_if_t<b, T>);
编译器会将其重写为:
template <bool b, typename T>
void foo(typename std::enable_if<b, T>::type);
原始的别名已经从等式中消失。
因此,像 T<X, Y>
这样的类型不能用来推断 T
作为别名模板,因为无论为 T<X, Y>
提供了什么类型 U
以匹配,如果它最初具有某个别名模板 A
的形式 A<X, Y>
,它将被替换为该别名模板所别名的内容,而 A
将不再存在。(但是,别名模板可以被推断为类模板的参数,该类模板具有模板模板参数,因为别名模板可以作为有效的模板模板参数)。
英文:
Whenever an alias template has arguments, it is immediately replaced with the type it aliases. So, for example, std::enable_if_t<true, int>
is immediately replaced by int
. This applies even in a dependent context; so for example if you have a function like this:
template <bool b, typename T>
void foo(std::enable_if_t<b, T>);
the compiler rewrites it to:
template <bool b, typename T>
void foo(typename std::enable_if<b, T>::type);
The original alias has disappeared from the equation.
It follows that a type like T<X, Y>
can't be used to deduce T
as an alias template because whatever type U
is provided for T<X, Y>
to match against, if it originally had the form A<X, Y>
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论