如何解决字符串中“operator=”的歧义重载

问题描述 投票:0回答:1

我正在尝试创建一个可以隐式转换为各种不同类型的类,包括基元类型和自定义定义的类。我希望能够转换为的类型之一是 std::string。下面是一个可以转换为各种不同类型的示例类。它抛出错误“错误:‘operator=’的重载不明确”。这是因为 std::string 有一个来自 CharT 的赋值运算符,编译器可以从 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 时,编译器不会抛出任何错误,因为它使用简单的构造函数而不是赋值运算符,但它在下一行出错。

任何帮助将不胜感激。

c++ string operator-overloading
1个回答
0
投票

std::string
有几个重载的
operator=
,其参数如下:
std::string
const char *
char
std::initializer_list

为了让你的代码正常工作,编译器需要选择一个,但至少有两个可能是合适的:

std::string
一个;和
char
一个,使用来自标量
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
true
可以专门变成
T
)。


当我在定义它的同一行上分配给 test_str 时

这是初始化,而不是赋值。它调用构造函数,而不是

operator=

© www.soinside.com 2019 - 2024. All rights reserved.