来自相同类的字符串和整数的隐式转换?

时间:2019-01-15 00:07:44

标签: c++11 c++14

如何对字符串和整数都具有隐式转换运算符?

简化代码:

#include <iostream>
#include <string>

struct Value
{
    operator std::string() const { return "abc"; }
    operator int() const { return 42; }
};

int main() {
    Value v;

    std::string s;
    s = v;  // error here

    // lines below not really needed
    int i;
    i = v;

    std::cout << s << " " << i << "\n";
}

c ++ 11编译器或更高版本。这些是错误,报告在字符串分配行上。

sandbox/casting_main.cpp: In function ‘int main()’:
sandbox/casting_main.cpp:14:7: error: ambiguous overload for ‘operator=’ (operand types are ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ and ‘Value’)
     s = v;  // error here
       ^
In file included from /usr/include/c++/5/string:52:0,
                 from /usr/include/c++/5/bits/locale_classes.h:40,
                 from /usr/include/c++/5/bits/ios_base.h:41,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from sandbox/casting_main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:550:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
       operator=(const basic_string& __str)
       ^
In file included from /usr/include/c++/5/string:52:0,
                 from /usr/include/c++/5/bits/locale_classes.h:40,
                 from /usr/include/c++/5/bits/ios_base.h:41,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from sandbox/casting_main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:569:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(_CharT) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
       operator=(_CharT __c)
       ^
In file included from /usr/include/c++/5/string:52:0,
                 from /usr/include/c++/5/bits/locale_classes.h:40,
                 from /usr/include/c++/5/bits/ios_base.h:41,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from sandbox/casting_main.cpp:1:
/usr/include/c++/5/bits/basic_string.h:587:7: note: candidate: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]
       operator=(basic_string&& __str)
       ^

显然,在c ++ 11标准中,有一个basic_string赋值运算符:

basic_string& operator=(charT c);

此赋值运算符引起编译器无法解决的歧义。

是否可以在同一个类中对字符串和int都使用隐式转换运算符?

2 个答案:

答案 0 :(得分:0)

如果您查看basic_string类,它会在分配operator=的三个重载之后进行定义:

// 1. Rvalue reference overload for basic_string
basic_string& operator=(basic_string&& __str);

// 2. Lvalue Reference overload for basic_string
basic_string& operator=(const basic_string& __str);

// 3. Overload for type value_type (set as char, see std::string typedef below)
basic_string& operator=(value_type __c);

value_type的定义如下:

template<class _CharT, class _Traits, class _Allocator>
class _LIBCPP_TEMPLATE_VIS basic_string
    : private __basic_string_common<true>
{
public:
    typedef _CharT                                       value_type;

std::string的定义为:

typedef basic_string<char, char_traits<char>, allocator<char> > string;

如您所见,在上述typedef中,_CharT被设置为char。现在,出现错误的行是:

   s = v;  // error here 

问题在于,对于上述分配,所有三个basic_string类型的运算符重载都是匹配的。

1.2.重载匹配是因为您定义了从Valuestd::string类型的隐式转换。 3.重载匹配是因为从intchar的隐式转换,而Value类型也隐含了对int的转换。

这是因为这种含糊不清的分配是错误的。我想唯一的解决方法是从您的Value类中删除一个隐式转换。

答案 1 :(得分:0)

这并不漂亮,但是可以使用SFINAE来完成。我们创建了一个模板转换运算符,但是限制为仅转换为int或std :: string,然后使用if constexpr执行正确的行为。

#include <type_traits>
#include <iostream>
#include <string>

struct Value
{
    template <typename type, typename = std::enable_if_t <std::is_same_v <type, std::string> || std::is_same_v <type, int>>>
    operator type () const {
        if constexpr (std::is_same_v <int, type>)
            return 42;
        else
            return "abc";
    }
};

int main() {
    Value v;

    std::string s;
    s = v;  // error here


    // lines below not really needed
    int i;
    i = v;

    std::cout << s << " " << i << "\n";
}