Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm trying to make a class that wraps a pointer around another type. With all of the extraneous bits removed, it looks like this:

template<typename T>
class field {
    std::unique_ptr<T> t_;
public:
    field() : t_(nullptr) {}
    field(const T &t) : t_(std::make_unique<T>(t)) {}
    field<T> &operator=(const T &t) {
        t_.reset(new T(t));
        return *this;

I can declare them by explicitly calling their constructors, but not with =, like so:

int main() {
    field<std::string> strA("Hello");
    field<std::string> strB = "Hello";
    return 0;

I get the error

-snip-/StringImplicit/main.cpp: In function ‘int main()’:
-snip-/StringImplicit/main.cpp:21:31: error: conversion from ‘const char [6]’ to non-scalar type ‘field<std::__cxx11::basic_string<char> >’ requested
   21 |     field<std::string> strB = "Hello";
      |                               ^~~~~~~

Where am I going wrong? I can't seem to use field<std::string>s in class constructors with raw strings without this conversion either, it throws the same error.

Edit: The end goal is something like discordpp::ApplicationCommandOption option{.type = 3, .name = "message", .description = "The message to echo", .required = true}; where all of those parameters are differently-typed fields.

  • std::string to field<std::string>.
  • There is a rule that implicit conversion can have at most one class-type conversion (the official term is "user-defined" conversion although this includes class types that are part of the standard library).

    To fix it you can either use your suggested fix; or manually specify one of the conversions, e.g:

    auto strB = field<std::string>("Hello");
    field<std::string> strC = std::string("Hello");
    field<std::string> strD = "Hello"s; 
    

    or you could add a constructor for const char[].

    SFINAE version of char array constructor (there will be better ways in C++20 I'm sure):

    template<size_t N, typename = std::enable_if_t<std::is_same_v<T, std::string>>>
    field(char const (&t)[N])
        : t_(std::make_unique<T>(t)) {}
                    Is there a way to define a constructor for const char[] for only field<std::string>? Not a great solution but it works.
    – Aido
                    Nov 11, 2021 at 3:06
                    @Aido yes - have the const char[] constructor and include a SFINAE or Concept to only enable it when T equals std::string.
    – M.M
                    Nov 11, 2021 at 3:07
                    What would the syntax for those be? I'm reading the pages on cppreference but I'm having a hard time with it.
    – Aido
                    Nov 11, 2021 at 3:11
                    Hmm, I maybe need to update for concepts but would field(const std::convertible_to<T> &ctt) : t_(std::make_unique<T>(t)) {} theoretically work?
    – Aido
                    Nov 11, 2021 at 3:16
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.