C++17 是否可以推导出“自动”非类型“模板”参数模式匹配具有显式非类型参数的模板?
Can C++17's deduced `auto` non-type `template` parameters pattern-match templates with explicit non-type parameters?
考虑这个例子 (also available on wandbox):
template <template <auto> class>
void test() { }
template <int>
struct X { };
尝试在 clang++
4.0 (trunk) 上实例化 test<X>()
导致编译错误:
error: no matching function for call to 'test'
test<X>();
^~~~~~~
note: candidate template ignored:
invalid explicitly-specified argument for 1st template parameter
void test() { }
我最初的 assumption/intuition 是 test
可用于匹配任何具有非类型参数的 template
。
但是,以下代码片段成功编译:
template <template <auto> class>
void test() { }
// vvvv
template <auto>
struct X { };
这是故意的吗?在 P0127R2.
中找不到任何结论
这绝对是有意为之。模板-模板参数只能匹配采用相同类型参数的模板。这个:
template <template <auto> class>
void test() { }
只能用 class 模板实例化,该模板可以采用 任何 种非类型参数。但是这个:
template <int>
struct X { };
不是这样的 class 模板。 X
只能用 int
实例化。它根本不符合模板模板参数的规范,因此出现错误。如果 test
想用指针类型实例化它的 class 模板怎么办?还是指向函数的指针或指向成员的指针?那是不可能的。
您的第二次尝试 template <auto> struct X { };
确实 匹配模板模板参数,因此格式正确。另请注意,反过来,让 test
采用 template <int> class
参数并传入 template <auto> struct X { };
也是格式正确的,因为参数比参数更通用。
相关写法在[temp.arg.template]:
A template-argument matches a template template-parameter P
when each of the template parameters in the template-parameter-list of the template-argument’s corresponding class template or alias template A
matches
the corresponding template parameter in the template-parameter-list of P
. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are
equivalent (14.5.6.1), and for template template-parameters, each of their corresponding template-parameters matches, recursively.
注意:等价措辞接受 auto
- auto
情况并拒绝 auto
- int
情况,但似乎也拒绝 int
- auto
案例(基于我的阅读)。我将尝试对此进行一些澄清。
除了让我感到好奇的 Barry 的回答之外,这里还有四种可能的组合和使用 Clang 4.0 (SVN) 的结果,see also on wandbox:
template <bool> struct obj_bool { }; // object taking a value of boolean type
template <auto> struct obj_auto { }; // object taking a value of deduced type
// ^^^^^^ Note: this is a template value argument (non-type template argument)
template <template <auto> typename> void fn_auto() { }
template <template <bool> typename> void fn_bool() { }
// ^^^^^^^^^^^^^^^^^^^^^^^^ Note: this is a template type argument
// ^^^^^^ taking a template value argument
int main() {
fn_bool<obj_bool>(); // #1 bool->bool OK (exact match)
fn_auto<obj_auto>(); // #2 auto->auto OK (exact match)
fn_bool<obj_auto>(); // #3 bool->auto OK (sub-set)
//fn_auto<obj_bool>(); // #4 auto->bool Error: no matching function.
}
由此可见,#1 和 #2 显然完全匹配,并且按预期工作。 #3 将调用模板上的 bool 实现,该模板不仅可以处理 bool,还可以处理所有类型,而 #4 将尝试调用一个定义,该定义期望一个通用对象(auto),其中一个对象仅提供可能性的子集(bool) .
模板函数 fn_auto
承诺可以为采用任何值类型(自动)的模板实例化。因此,只给它一个可能性的子集 (bool) 违反了这个承诺。
虽然不是很明显,但限制是有道理的。很抱歉我的措辞不符合 C++ 标准。
考虑这个例子 (also available on wandbox):
template <template <auto> class>
void test() { }
template <int>
struct X { };
尝试在 clang++
4.0 (trunk) 上实例化 test<X>()
导致编译错误:
error: no matching function for call to 'test'
test<X>();
^~~~~~~
note: candidate template ignored:
invalid explicitly-specified argument for 1st template parameter
void test() { }
我最初的 assumption/intuition 是 test
可用于匹配任何具有非类型参数的 template
。
但是,以下代码片段成功编译:
template <template <auto> class>
void test() { }
// vvvv
template <auto>
struct X { };
这是故意的吗?在 P0127R2.
中找不到任何结论这绝对是有意为之。模板-模板参数只能匹配采用相同类型参数的模板。这个:
template <template <auto> class>
void test() { }
只能用 class 模板实例化,该模板可以采用 任何 种非类型参数。但是这个:
template <int>
struct X { };
不是这样的 class 模板。 X
只能用 int
实例化。它根本不符合模板模板参数的规范,因此出现错误。如果 test
想用指针类型实例化它的 class 模板怎么办?还是指向函数的指针或指向成员的指针?那是不可能的。
您的第二次尝试 template <auto> struct X { };
确实 匹配模板模板参数,因此格式正确。另请注意,反过来,让 test
采用 template <int> class
参数并传入 template <auto> struct X { };
也是格式正确的,因为参数比参数更通用。
相关写法在[temp.arg.template]:
A template-argument matches a template template-parameter
P
when each of the template parameters in the template-parameter-list of the template-argument’s corresponding class template or alias templateA
matches the corresponding template parameter in the template-parameter-list ofP
. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are equivalent (14.5.6.1), and for template template-parameters, each of their corresponding template-parameters matches, recursively.
注意:等价措辞接受 auto
- auto
情况并拒绝 auto
- int
情况,但似乎也拒绝 int
- auto
案例(基于我的阅读)。我将尝试对此进行一些澄清。
除了让我感到好奇的 Barry 的回答之外,这里还有四种可能的组合和使用 Clang 4.0 (SVN) 的结果,see also on wandbox:
template <bool> struct obj_bool { }; // object taking a value of boolean type
template <auto> struct obj_auto { }; // object taking a value of deduced type
// ^^^^^^ Note: this is a template value argument (non-type template argument)
template <template <auto> typename> void fn_auto() { }
template <template <bool> typename> void fn_bool() { }
// ^^^^^^^^^^^^^^^^^^^^^^^^ Note: this is a template type argument
// ^^^^^^ taking a template value argument
int main() {
fn_bool<obj_bool>(); // #1 bool->bool OK (exact match)
fn_auto<obj_auto>(); // #2 auto->auto OK (exact match)
fn_bool<obj_auto>(); // #3 bool->auto OK (sub-set)
//fn_auto<obj_bool>(); // #4 auto->bool Error: no matching function.
}
由此可见,#1 和 #2 显然完全匹配,并且按预期工作。 #3 将调用模板上的 bool 实现,该模板不仅可以处理 bool,还可以处理所有类型,而 #4 将尝试调用一个定义,该定义期望一个通用对象(auto),其中一个对象仅提供可能性的子集(bool) .
模板函数 fn_auto
承诺可以为采用任何值类型(自动)的模板实例化。因此,只给它一个可能性的子集 (bool) 违反了这个承诺。
虽然不是很明显,但限制是有道理的。很抱歉我的措辞不符合 C++ 标准。