在C++中从用户定义类型到基本类型的隐式转换

Mat*_*ggs 8 c++ implicit-cast

我能够找到大量关于从int到用户定义类型的隐式转换的信息.即如果构造函数将int作为其参数并且不以"explicit"开头,则可能发生隐式转换.

如果我希望我的类隐式转换 int怎么办?

例如,需要在SimpleClass内部或外部添加什么函数,以便main函数将编译并输出"1"到控制台?(看评论)

#include <iostream>

class SimpleClass
{
private:
    int m_int;
public:
    SimpleClass(int value)
    : m_int(value) {}
};

int main(int argc, const char * argv[])
{
    SimpleClass simpleclass(1);
    int i = simpleclass; // does not complile
    std::cout << i << std::endl; // should output "1" to the console
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Jan*_*dec 12

隐式转换可以通过两种方式定义:

  • 非显式单参数构造函数.
  • 非显式转换函数(又称转换运算符),N3337 12.3.2

后者允许定义从类类型到基本类型的转换.只需添加

class SimpleClass {
   // ...
   operator int() const;
};

SimpleClass::operator int() const
{
   return m_int;
}
Run Code Online (Sandbox Code Playgroud)

  • 这些是**转换**,而不是**转换**.您可以在源代码中编写一个强制转换来告诉编译器进行转换. (4认同)

Che*_*Alf 6

技术.

转换为(几乎)任何类型T都可以由operator T成员函数执行.

默认情况下,它是隐式调用的,如果您声明它const,也可以在const对象上调用它.

从而:

struct MyType
{
    operator int() const { return 1; }
};
Run Code Online (Sandbox Code Playgroud)

问题…

对基本类型进行隐式转换允许所有内置运算符的自由播放,包括

  • 算术运算符.
  • 布尔运算符.
  • 关系运算符.

所以你最好确保所有这些按照你想要的方式工作.

这可能是很多工作!

涉及类型实例的调用的重载解析也存在潜在问题.

简而言之,隐式转换为int,或指针或任何内置类型,通常花费超过它的价值.

值得一提的例外是在库中使用了很多类.

你可以做些什么呢.

避免隐式转换,但确实提供显式转换.

最好的一般显式转换是,恕我直言,一个命名成员函数.

另一种方法是以operator T关键字为前缀,explicit在C++ 11及更高版本中支持此用法(在C++ 03中它只能用于构造函数).

如果您希望输出via <<的行为就像执行隐式转换一样,那么只需定义一个operator<<.

类似地,对于隐式转换似乎是一般解决方案的其他情况:只需定义适合该特定情况的内容,并避免引入一般的隐式转换.


要提供对内置类型的隐式转换,同时避免内置运算符的"全部免费",您可以使用模板化类型转换,例如:

#include <iostream>

template< class A, class B > struct Is_t_;

template< class Type > struct Is_t_<Type, Type> { using T = void; };

template< class A, class B >
using If_is_ = typename Is_t_<A, B>::T;

struct Bad_string
{
    operator const char* () const { return "666!"; }
    Bad_string( char const* = 0 ) {}
};

auto operator==( Bad_string const&, Bad_string const& )
    -> bool
{ return true; }

struct Good_string
{
    template< class Type, class Enabled_ = If_is_<const char*, Type>>
    operator Type() const { return "42 :)"; }

    Good_string( char const* = 0 ) {}
};

auto operator==( Good_string const&, Good_string const& )
    -> bool
{ return true; }

#if defined( DO_GOOD )
    using String = Good_string;
#elif defined( DO_BAD )
    using String = Bad_string;
#else
#   error "Define either DO_GOOD or DO_BAD, please."
#endif

auto main() -> int
{
    String a, b;
    (void) (a == "alfalfa");        // Errs for Bad_string
    (void) (a + 1);                 // Compiles for Bad_string.
}
Run Code Online (Sandbox Code Playgroud)

具有讽刺意味的是,在DO_GOOD定义时,此代码崩溃了Visual C++ 2015 update 1编译器,即所谓的"ICE"(内部编译器错误).

该编译器的变通方法是定义If_is_

template< class A, class B >
using If_is_ = std::enable_if_t< std::is_same<A, B>::value >;
Run Code Online (Sandbox Code Playgroud)