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

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

使用 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)。

Here是一个用例:

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 成为 class,它只接受一个模板参数,如 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,so gcc can pass compile。这是clang的错误吗?

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

When N is zero, the instantiation of the expansion produces an empty list. Such an instantiation does not alter the syntactic interpretation of the enclosing construct, even in cases where omitting the list entirely would otherwise be ill-formed or would result in an ambiguity in the grammar. [ Example:

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

 — end example ]

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

当然,如果包 不是 空的,那么我们将传递太多参数, 错误-形成。但事实并非如此。