Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot convert Type in initialization

I think I miss something and I don't know what exactly. Let's take a look at code snippet.

template <typename T>
struct Foo { 
    Foo (int n, int p, string s, T t = {})
    : m_n {n}, m_p {p}, m_s {s}, m_t {t}
    {}

    const int m_n;
    const int m_p;
    const string m_s;
    T m_t;
};

And usage looks like this:

Foo<int> f_int1 {1, 2, "A", 155};
Foo<int> f_int2 {1, 2, "A"};

Everything is like intended. But when I want to have a user defined type as a T parameter of Foo, some errors occur. Consider:

struct Boo {
    int z;
    int l;
};

And usage:

Foo<Boo> f_boo1 {1, 2, "A"};
Foo<Boo> f_boo2 {1, 2, "A", {1, 2}};

These both instructions give (gcc 4.8.1):

cannot convert ‘Boo’ to ‘int’ in initialization

I can create Boo objects like this:

Boo boo1 {};
Boo boo2 {1, 2};

So, could you tell me where the problem is?

Possible solution:

struct Boo {
    Boo () : z {}, l {} {}
    Boo (int p1, int p2) : z {p1}, l {p2} {}

    int z;
    int l;
};

And both below instructions work as intended:

Foo<Boo> f_boo1 {1, 2, "A"};
Foo<Boo> f_boo2 {1, 2, "A", {1, 2}};

For me, that's ok, I don't see any reason why not to add two constructors to the class, but what if the type is not mine? Should I write simple wrapper with the constructors?

Thanks, Artur

like image 686
Artur Pyszczuk Avatar asked Jan 24 '15 17:01

Artur Pyszczuk


1 Answers

That's because you're trying to perform aggregate initialization on Boo. See §8.5.4/3:

List-initialization of an object or reference of type T is defined as follows:

— If T is an aggregate, aggregate initialization is performed (8.5.1).

You're intending to copy-construct your Boo... but really you're doing aggregate initialization, which leads to trying to construct int z from a Boo, hence the error

error: no viable conversion from 'Boo' to 'int'

Note that you could reproduce your problem in much less code and without any templates:

Boo b;
Boo b2{b}; // error

The fix is simple. Just don't use list-initialization:

template <typename T>
struct Foo { 
    Foo (int n, int p, string s, T t = {})
    : m_n {n}, m_p {p}, m_s {s}, m_t(t)
    //                           ^^^^^^
{};
like image 114
Barry Avatar answered Nov 16 '22 23:11

Barry