Home > Net >  Conversion from `const char[]` to non-scalar type requested
Conversion from `const char[]` to non-scalar type requested

Time:11-11

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.

CodePudding user response:

The problem is that two class-type conversions are required:

  • const char[6] to std::string
  • 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)) {}
  • Related