c++ 如何解决字符串中“operator=”的二义性重载

a0x5cqrl  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(98)

我试图创建一个类,它可以隐式转换为各种不同的类型,包括原语和自定义类。我希望能够转换为的类型之一是std::string。下面是一个可以转换为各种不同类型的示例类。它抛出错误“error:ambiguous overload for 'operator='"。这是因为std::string有一个来自ChartT的赋值运算符,编译器可以从int创建它。我的问题是,有没有可能有一个类既可以隐式转换为整数类型,也可以隐式转换为字符串类型?

class Test {
public:
    operator double() const {
        return 3.141592;
    }
    operator std::int64_t() const {
        return -999;
    }
    operator std::uint64_t() const {
        return 999;
    }
    operator bool() const {
        return true;
    }
    operator std::string() const {
        return "abcd";
    }
};

int main(int argc, char** argv) {
    std::string test_str = Test();
    test_str = Test();
    std::cout << test_str;
}

字符串
有趣的是,当我在定义test_str的同一行上赋值给它时,编译器不会抛出错误,因为它使用的是简单的构造函数而不是赋值运算符,但是它在下面的一行上出错了。
任何帮助将不胜感激。

7rfyedvj

7rfyedvj1#

std::string有几个重载的operator=,参数如下:std::stringconst char *charstd::initializer_list
为了使代码正常工作,编译器需要选择一个,但至少有两个可能是合适的:std::stringchar,使用标量operator的隐式转换。尽管后者会在以后引起歧义,但编译器似乎没有达到这一点。
解决方案是进行一个模板化的转换operator,并使用SFINAE将其限制为特定类型:
然后以下工程:

template <auto V, typename, typename...>
inline constexpr auto value = V;

template <typename T, typename ...P>
concept one_of = (std::same_as<T, P> || ...);

class Test
{
  public:
    template <one_of<int, float, std::string> T>
    operator T() const
    {
        if constexpr (std::same_as<T, int>)
            return 42;
        else if constexpr (std::same_as<T, float>)
            return 42;
        else if constexpr (std::same_as<T, std::string>)
            return "foo";
        else
            static_assert(value<false, T>, "This shouldn't happen.");
    }
};

字符串
static_assert并不是必需的,因为我们已经有了requires,它只是在你向requires添加更多类型而忘记了一个分支时提供一个更好的错误。
注意value<false, T>而不是false。尝试将false直接放在那里会导致某些编译器无条件地发出错误,即使没有采用分支使用依赖于T的表达式会使编译器将测试延迟到实际的示例化(因为就它所知,value可以被专门化为某些Ttrue)。
当我在定义test_str的同一行上赋值时,
这是一个初始化,而不是赋值。它调用一个构造函数,而不是operator=

相关问题