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++ 标准。