当foo是接受单个模板参数的结构时,'foo<Type1, Types...>'是否合法?

is `foo<Type1, Types...>` legal when foo is a struct which accepts single template parameter?

本文关键字:foo Types Type1 lt gt 是否 参数 单个模 结构      更新时间:2023-10-16

当玩libstdcxx的test_property时:

template<template<typename...> class Property,
       typename Type1, typename... Types>
constexpr bool
test_property(typename Property<Type1, Types...>::value_type value)
{
    return (Property<Type1, Types...>::value == value
      && Property<Type1, Types...>::type::value == value);
 }

class Property接受至少 1 个模板参数 ( Type1 )。

下面是一个用例:

static_assert(test_property<is_copy_assignable, ExceptMoveAssignClass>(false), "");

但是我发现 clang 不能很好地使用这个函数:

prog.cc:29:3: error: no matching function for call to 'test_property'
                test_property<std::is_copy_assignable, DeletedMoveAssignClass>(false);
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:12:1: note: candidate template ignored: substitution failure [with Property = std::is_copy_assignable, Type1 = DeletedMoveAssignClass]: too many template arguments for class template 'is_copy_assignable'
test_property(typename Property<Type1, Types...>::value_type value)
^                      ~~~~~~~~
1 error generated.

根本原因是 clang 不允许class Property是只接受一个模板参数(如 template< class T > struct is_copy_assignable; )的类。一旦class Property被修改成Property<Type1>,它就会编译成功:

template<template<typename...> class Property, typename Type1>
constexpr bool
ya_test_property(typename Property<Type1>::value_type value)
{
    return (Property<Type1>::value == value
        && Property<Type1>::type::value == value);
}

这是演示 https://wandbox.org/permlink/LlL1o57Yted5WZo5

当然,这个函数来自libstdcxx,所以gcc可以通过编译。这是叮当的虫子吗?

如果我正确解释 [temp.variadic]/7,看起来像一个 Clang 错误:

当 N 为零时,扩展的实例化将生成一个空 列表。这样的实例化不会改变句法 封闭结构的解释,即使在以下情况下 完全省略该列表将是不正确的格式或 导致语法不明确。[ 示例

template<class... T> struct X : T... { };
template<class... T> void f(T... values) {
  X<T...> x(values...);
}
template void f<>();    // OK: X<> has no base classes
                        // x is a variable of type X<> that is value-initialized

— 结束示例 ]

同样,虽然std::is_copy_assignable<ExceptMoveAssignClass , >格式不正确,但空包不应该让我们处于这种状态。它应该等价于 std::is_copy_assignable<ExceptMoveAssignClass> ,这是格式正确的。

当然,如果包不是空的,那么我们就会传递太多的参数,这是格式不正确的。但事实并非如此。