Can't assign string literal to boxed std::string vector

冷暖自知 提交于 2019-12-03 12:00:27

c currently need 2 implicit user conversions (const char [N] -> std::string -> String) whereas only one is allowed.

You may add template constructor to Box

template<typename T>
class Box {
public:
    Box() = default;
    Box(const Box&) = default;
    Box(Box&&) default;
    ~Box() = default;

    Box& operator=(const Box&) = default;
    Box& operator=(Box&&) = default;

    template <typename U0, typename ...Us,
              std::enable_if_t<std::is_constructible<T, U0, Us...>::value
                               && (!std::is_same<Box, std::decay_t<U0>>::value
                                  || sizeof...(Us) != 0)>* = nullptr>
    Box(U0&& u0, Us&&... us) : _value(std::forward<U0>(u0), std::forward<Us>(us)...) {}
private:
    T _value;
    /* ... */
};

Demo Demo2

Looking at your source code in the main function part only:

int main(int argc, char* argv[]) {
    String a("abc");
    std::vector<String> b = { std::string("abc"), std::string("def") };

    // error C2664: 'Box<std::string>::Box(const Box<std::string> &)' :
    // cannot convert argument 1 from 'const char' to 'const std::string &'
    std::vector<String> c = { "abc", "def" };
}

Your first line of code:

String a("abc");

Is using the typedef version of Box<std::string> which this class template takes a const T& and since this version of the template is expecting a std::string it is using std::string's constructor to construct a std::string from a const char[3] and this is okay.

Your next line of code:

std::vector<String> b = { std::string("abc"), std::string("def") };

Is a std::vector<T> of the same above. So this works as well since you are initializing the vector<T> with valid std::string objects.

In your final line of code:

std::vector<String> c = { "abc", "def" };

Here are you declaring c as a vector<T> where T is a typedef version of Box<std::string> however you are not initializing the std::vector<T> with Box<std::string> types. You are trying to initialize it with const char[3] objects or string literals.

You can try doing this for the third line: I haven't tried to compile this but I think it should work.

std::vector<String> c = { String("abc"), String("def") };

EDIT -- I meant to use the constructor for String and not std::string made the appropriate edit.

You could use a helper function that creates the corresponding type:

template <typename T,typename R>
Box<T> make_boxed(const R& value){
    return Box<T>(value);
}

it may seem like additional complication that one has to specify the T, on the other hand you can use auto for the returned type. Complete example:

#include <string>

template<typename T>
class Box {
public:
    Box(const T& value) : _value(value) {};
private:
    T _value;
    /* ... */
};

typedef Box<std::string> String;

int main(int argc, char* argv[]) {
    auto a = make_boxed<std::string>("asd");
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!