I created a factory function template:
template <typename M, typename... Args>
std::shared_ptr<M> create(Args... args)
{
return std::make_shared<M>(args...);
}
And a simple container:
struct Group {
std::vector<int> vec;
Group(std::initializer_list<int> il) : vec(il) {}
};
Then I try to create a Group
int main()
{
auto gr = create<Group>({1, 2, 3});
return 0;
}
This doesn't compile,
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)
^
but if I use a temporary variable:
int main(int argc, char *argv[])
{
std::initializer_list<int> il = {1, 2, 3};
auto gr = create<Group>(il);
return 0;
}
it does. Why?
What is the recommended solution for such case?
A template parameter cannot be deduced from an initializer list (it's a non-deduced context), but can from an expression of type std::initializer_list<something>
. The two are not the same.
[temp.deduct.call]/1 Template argument deduction is done by comparing each function template parameter type (call it
P
) with the type of the corresponding argument of the call (call itA
) as described below. If removing references and cv-qualifiers fromP
givesstd::initializer_list<P'>
for someP'
and the argument is an initializer list (8.5.4), then deduction is performed instead for each element of the initializer list, takingP'
as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context (14.8.2.5). [ Example: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
—end example ]
From cppreference :
A braced-init-list is not an expression and therefore has no type, eg
decltype({1,2})
is ill-formed. Having no type implies that template type deduction cannot deduce a type that matches a braced-init-list , so given the declarationtemplate<class T> void f(T);
the expressionf({1,2,3})
is ill-formed.
There is one exception though: auto a = { 1, 2 };
results in a
being a std::initializer_list
. But this is only in auto
type deducing, not for templates.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.