可变参数模板不适用于初始化列表

mar*_*trz 4 c++ variadic-functions variadic-templates c++11

我创建了一个工厂功能模板:

template <typename M, typename... Args>
std::shared_ptr<M> create(Args... args)
{
    return std::make_shared<M>(args...);
}
Run Code Online (Sandbox Code Playgroud)

还有一个简单的容器:

struct Group {
    std::vector<int> vec;
    Group(std::initializer_list<int> il) : vec(il) {}
};
Run Code Online (Sandbox Code Playgroud)

然后我尝试创建一个组

int main()
{
    auto gr = create<Group>({1, 2, 3});
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这不会编译,

error: no matching function for call to 'create'
    auto gr = create<Group>({1, 2, 3});
candidate function not viable: requires 0 arguments, but 1 was provided
std::shared_ptr<M> create(Args... args)
                   ^
Run Code Online (Sandbox Code Playgroud)

但是如果我使用一个临时变量:

int main(int argc, char *argv[])
{
    std::initializer_list<int> il = {1, 2, 3};
    auto gr = create<Group>(il);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

是的。为什么?

对于这种情况,推荐的解决方案是什么?

Igo*_*nik 5

模板参数不能从初始值设定项列表(它是非推断上下文)中推导,而可以从type表达式中推导std::initializer_list<something>。两者不一样。

[temp.deduct.call] / 1模板参数推导是通过将每个函数模板参数类型(称为P)与调用的相应参数类型(称为A)进行比较,如下所述。如果删除的引用和cv修饰符从P给出std::initializer_list<P'>一些P'和参数为初始化值列表(8.5.4),然后进行扣除,而不是用于初始化列表中的每个元素,以P'作为函数模板参数类型和初始值设定元素作为其论点。否则,使用初始化列表参数将参数视为非推论上下文(14.8.2.5)。[ 示例:

template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
f({1,"asdf"}); // error: T deduced to both int and const char*

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
Run Code Online (Sandbox Code Playgroud)

—结束示例 ]