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

前端 未结 3 2000
暖寄归人
暖寄归人 2021-02-13 16:17

This is a simplified version of my type system:

#include 
#include 

template
class Box {
public:
    Box(const T&a         


        
相关标签:
3条回答
  • 2021-02-13 16:30

    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.

    0 讨论(0)
  • 2021-02-13 16:37

    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");
    }
    
    0 讨论(0)
  • 2021-02-13 16:50

    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

    0 讨论(0)
提交回复
热议问题