too many arguments to function std::make_shared<vector>
Asked Answered
D

1

6

I am missing something with std::make_shared. Can't it resolve the type of a std::initializer_list, or am I doing something else wrong?

#include <vector>
#include <memory>

class A {};

int main()
{
    A a;
    std::vector<A> veca{A(), A{}, a}; // this works ofc
    std::vector<A> vecb({A(), A{}, a}); // this too

    std::make_shared<std::vector<A>>(vecb); // and this, ofc
    std::make_shared<std::vector<A>>({a}); // what's wrong here?
    return 0;
}

Error:

main.cpp:21:41: error: too many arguments to function ‘std::shared_ptr<_Tp1> std::make_shared(_Args&& ...) [with _Tp = std::vector; _Args = {}]’
     std::make_shared<std::vector<A>>({a});
                                         ^
In file included from /usr/include/c++/6/memory:82:0,
                 from main.cpp:10:
/usr/include/c++/6/bits/shared_ptr.h:632:5: note: declared here
     make_shared(_Args&&... __args)
     ^~~~~~~~~~~

Live example: https://onlinegdb.com/r1DlHquDL

Dentation answered 6/4, 2020 at 11:40 Comment(7)
Does this answer your question? std::shared_ptr and initializer lists. But there are no exact reasons why this happens :(Smog
try "std::make_shared<std::vector<A>>(vector<A>{a});" I think its related #56484106Shanan
@user3365922 That answer says that it's a compiler issue or perfect forwarding not being perfect. I now I can cast the braces to a std::vector<A> or a initializer list, but I was looking for something more elegantDentation
Relevant part of the latest C++ Draft: temp.deduct.call/1. I believe this applies: Otherwise, an initializer list argument causes the parameter to be considered a non-deduced contexts, but the error message is kind-of misleading, so I am not 100% sure. With Clang, the substitution fails as expected. Minimal demo: godbolt.org/z/HvDPms.Psychoanalysis
@DanielLangr looks good to me. The error message is misleading indeed, but clang gives me a "no matching function for call [...]" instead, soo...Stifle
The code of more-minimal demo (can't edit anymore my previous comment): template <typename... Ts> void f(Ts&&...); int main() { f({1}); }.Psychoanalysis
The non-deduced context is what I was looking for, so if anyone can paste this into an answer, I would be grateful :-) Oh, and that the error message is misleading tooDentation
P
3

Consider the following minimal example of your problem:

template <typename... Ts>
void f(Ts&&...);  // replacement for std::make_shared

int main()
{  
  f({1});
}

This case is described in the C++ Standard in [temp.deduct.call/1]:

Template argument deduction is done by comparing each function template parameter type (call it P) that contains template-parameters that participate in template argument deduction with the type of the corresponding argument of the call (call it A) as described below. If removing references and cv-qualifiers from P gives std::initializer_list<P′> or P′[N] for some P′ and N and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list independently, taking P′ as separate function template parameter types P′i and the ith initializer element as the corresponding argument. In the P′[N] case, if N is a non-type template parameter, N is deduced from the length of the initializer list. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context ([temp.deduct.type]).

In your case, the last sentence applies. Interestingly, the error message says something else with GCC, which is weird. With Clang, the error message is clear:

error: no matching function for call to 'f'

note: candidate template ignored: substitution failure: deduced incomplete pack <(no value)> for template parameter 'Ts'

Psychoanalysis answered 6/4, 2020 at 12:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.