1

I have the following code:

#include <complex>
#include <tuple>
#include <unordered_map>
using namespace std;

int main()
{
    unordered_map<string, complex<double>> um;
    um.emplace(piecewise_construct, make_tuple("test1"), make_tuple(1,1));// works
    // um.emplace("test2", {1,1}); // error here  
    complex<double> z{1,1};
    um.emplace("test3", z); // this works
}

I do not completely understand why am I getting an error on the commented line. The unordered_map is emplacing a pair<string, complex<double>>, and complex<double> has a initialization list type constructor, why cannot then the pair can be constructed in place? If I replace the init-list {1,1} with a previously constructed complex<double>, then it works.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 5
    `{1,1}` is not an expression an does not have a type. Hence, the function template `emplace` cannot deduce its type. You could specify the type explicitly: `um.emplace>("test2, {1,1});` but I wouldn't recommend it. – dyp Jul 14 '14 at 18:49
  • @dyp You can probably just explicitly construct the complex in the parameters, rather than specifying both types. – T.C. Jul 14 '14 at 18:57
  • @T.C. Yes, that's pretty much what the last line does. `um.emplace("test3", complex{1,1});` should work. – dyp Jul 14 '14 at 18:59
  • Actually I am a bit confused. Isn't `{...}` of type `std::initializer_list`? And if the object inside the pair provides an `initializer_list` ctor, shouldn't then the `complex` be constructible from the init list? So basically the `template emplace(Args...)` has the second argument of type `initializer_list`, which should be convertible (implicitly) to `complex` – vsoftco Jul 14 '14 at 19:25
  • 1
    @vsoftco Yeah... unfortunately, `{..}` has been used for both *uniform initialization* and to create `std::initializer_list`s. This leads to quite some ambiguity and misunderstandings. *Uniform initialization*, aka *list-initialization* is a general form of initialization that *can* lead to the creation of a `std::initializer_list`. However, the `{..}` (called a *braced-init-list*) in an initialization doesn't have a type itself. Constructors with a parameter of the form `std::initializer_list` are called initalizer-list-constructors. Neither `std::pair` nor `std::complex` has one. – dyp Jul 14 '14 at 19:31
  • @dyp, ahhh ok, have to brush up on my `C++11` :) So if `complex` would have had a ctor of type `std::initializer_list`, then my example would've worked. – vsoftco Jul 14 '14 at 19:36
  • No, the problem in your code is that `emplace` is something like `template void emplace(Args&&...);` so that it has to deduce a type for each argument. `{1,1}` does not have a type, so this function template cannot produce a (function) parameter for that argument. – dyp Jul 14 '14 at 19:38

0 Answers0