Can a Cast Operator Be Explicit

Can a cast operator be explicit?

Yes and No.

It depends on which version of C++, you're using.

  • C++98 and C++03 do not support explicit type conversion operators
  • But C++11 does.

Example,

struct A
{
//implicit conversion to int
operator int() { return 100; }

//explicit conversion to std::string
explicit operator std::string() { return "explicit"; }
};

int main()
{
A a;
int i = a; //ok - implicit conversion
std::string s = a; //error - requires explicit conversion
}

Compile it with g++ -std=c++0x, you will get this error:

prog.cpp:13:20: error: conversion from 'A' to non-scalar type 'std::string' requested

Online demo : http://ideone.com/DJut1

But as soon as you write:

std::string s = static_cast<std::string>(a); //ok - explicit conversion 

The error goes away : http://ideone.com/LhuFd

BTW, in C++11, the explicit conversion operator is referred to as "contextual conversion operator" if it converts to boolean. Also, if you want to know more about implicit and explicit conversions, read this topic:

  • Implicit VS Explicit Conversion

Hope that helps.

How to interpret the explicit cast operator

Type Casting

It isn't the syntax you use when casting that determines how that cast is performed, it's the context based on the variable types.

When the compiler sees that you're trying to cast from Money to double, it tries to figure out a way to accomplish that - in every case, it uses the Money::operator double() operator because in every case double was specified as the target type.

C++ almost always allows you to accomplish one task in multiple different ways due to historical reasons; even its name alludes to its original goal: extending the C language.

Consider the following syntaxes:

Money balance(100.0);

// C-Style Cast
(double)balance; //< double with value 100.0

// Functional Cast
double(balance); //< double with value 100.0
double{ balance }; //< double with value 100.0

// Static Cast
static_cast<double>(balance); //< double with value 100.0

Once this is compiled, there isn't really any difference in which syntax you used; all of them call Money::operator double().

Of course, casting is always subject to operator precedence.

Note: While in this case all of the approaches are the same, this is not true in all cases.

Whenever possible, use static_cast instead of c-style or functional casts - you can read more about why here.

Explicit vs. Implicit Type Casting

Consider the following objects:

  • Money is your class.
  • Cash is a copy of Money that allows implicit casting.
class Money
{
public:
Money() : amount{ 0.0 } {};
Money(double _amount) : amount{ _amount } {};

// This is an explicit casting operator:
explicit operator double() const { return amount; }
private:
double amount;
};

class Cash
{
public:
Cash() : amount{ 0.0 } {};
Cash(double _amount) : amount{ _amount } {};

// This is an implicit casting operator
operator double() const { return amount; }
private:
double amount;
};

Now consider the following function that accepts a double:

void BuySomething(double amount) {}

In order to BuySomething() with Money, we must explicitly cast it to double first:

Money money(500.0);

BuySomething(static_cast<double>(money));
BuySomething((double)money);
BuySomething(double(money));
BuySomething(double{ money });

// We can also just call the operator directly:
BuySomething(money.operator double());

However, we can BuySomething() with Cash without explicitly casting it first:

Cash cash(500.0);

BuySomething(cash);

// You can still use explicit casting:
BuySomething(static_cast<double>(cash));
BuySomething((double)cash);
BuySomething(double(cash));
BuySomething(double{ cash });

BuySomething(cash.operator double())

This is because when the compiler sees BuySomething(cash);, it knows that BuySomething() doesn't accept Cash - it accepts double - so rather than just throwing an error, it tries to figure out a way to convert Cash to double, and in the process finds our conversion operator.

If you notice something wrong with my explaination, let me know in the comments.

C#: Writing an explicit cast operator for an internal class in another .NET assembly

No, there is not. Even if the class was public and you did have an explicit conversion to VendorInternalTypeA from your class, the code in question is casting an expression of type object to VendorInternalTypeA not an expression of your custom type, so the explicit conversion operator won't be used even if it exists.

User defined conversion operators are bound at compile time when the compile time type of the expression being converted has a user defined operator to the type it's being converted to.

Require operator double() to be explicitly called via static_castdouble(x)

Yes, you can mark conversion operators explicit since C++11.

explicit operator double() { /* ... */ }

This will prevent copy-initialization, e.g.,

double y = x;
return x; // function has double return type
f(x); // function expects double argument

while allowing explicit conversions such as

double y(x);
double y = static_cast<double>(x);

overloading explicit CAST operator

You can implement custom type casting using the conversion operators implicit or explicit.

Conversion operators can be explicit or implicit. Implicit conversion operators are easier to use, but explicit operators are useful when you want users of the operator to be aware that a conversion is taking place. This topic demonstrates both types.

Example

This is an example of an explicit conversion operator. This operator converts from the type Byte to a value type called Digit. Because not all bytes can be converted to a digit, the conversion is explicit, meaning that a cast must be used, as shown in the Main method.

struct Digit
{
byte value;

public Digit(byte value) //constructor
{
if (value > 9)
{
throw new System.ArgumentException();
}
this.value = value;
}

public static explicit operator Digit(byte b) // explicit byte to digit conversion operator
{
Digit d = new Digit(b); // explicit conversion

System.Console.WriteLine("Conversion occurred.");
return d;
}
}

class TestExplicitConversion
{
static void Main()
{
try
{
byte b = 3;
Digit d = (Digit)b; // explicit conversion
}
catch (System.Exception e)
{
System.Console.WriteLine("{0} Exception caught.", e);
}
}
}
// Output: Conversion occurred.

This example demonstrates an implicit conversion operator by defining a conversion operator that undoes what the previous example did: it converts from a value class called Digit to the integral Byte type. Because any digit can be converted to a Byte, there's no need to force users to be explicit about the conversion.

struct Digit
{
byte value;

public Digit(byte value) //constructor
{
if (value > 9)
{
throw new System.ArgumentException();
}
this.value = value;
}

public static implicit operator byte(Digit d) // implicit digit to byte conversion operator
{
System.Console.WriteLine("conversion occurred");
return d.value; // implicit conversion
}
}

class TestImplicitConversion
{
static void Main()
{
Digit d = new Digit(3);
byte b = d; // implicit conversion -- no cast needed
}
}
// Output: Conversion occurred.

from: http://msdn.microsoft.com/en-us/library/85w54y0a(v=VS.100).aspx

Do be careful with this, for readability it can often be confusing to see one type magically cast to another - people don't always first think that there are conversion operators in play.

Explicit/implicit cast operator fails when using LINQ's .Cast() operator

When you define explicit/implicit cast operators, they are bound at call-sites at compile-time. That's why the first line works: the compiler can work out all the type information needed, and so it can substitute your custom explicit cast operator for the default one.

However, since the Cast<T> just performs a generic cast, the compiler doesn't know about your operator, and thus it is ignored. Result: invalid cast exception.

You can get around this by instead performing a .Select(x => (DatabaseInfo)x). Alternatively, you could add on a method called ToDatabaseInfo(), so that you're not hiding what's actually going on.

When can I use explicit operator bool without a cast?

The standard mentions places where a value may be "contextually converted to bool". They fall into four main groups:

Statements


  •    if (t) /* statement */;

  •    for (;t;) /* statement */;

  •    while (t) /* statement */;

  •    do { /* block */ } while (t);

Expressions


  •    !t

  •    t && t2

  •    t || t2

  •    t ? "true" : "false"

Compile-time tests


  •    static_assert(t);

  •    noexcept(t)

  •    explicit(t)

  •    if constexpr (t)

The conversion operator needs to be constexpr for these.

Algorithms and concepts


  •    NullablePointer T

    Anywhere the Standard requires a type satisfying this concept (e.g. the pointer type of a std::unique_ptr), it may be contextually converted. Also, the return value of a NullablePointer's equality and inequality operators must be contextually convertible to bool.


  •    std::remove_if(first, last, [&](auto){ return t; });

    In any algorithm with a template parameter called Predicate or BinaryPredicate, the predicate argument can return a T.


  •    std::sort(first, last, [&](auto){ return t; });

    In any algorithm with a template parameter called Compare, the comparator argument can return a T.

(source1, source2)


Do be aware that a mix of const and non-const conversion operators can cause confusion:

  • Why doesn't explicit bool() conversion happen in contextual conversion?
  • Why does the explicit operator bool not in effect as expected?

Why/when is it important to specify an operator as explicit?

The C# language specification says under 10.10.3 Conversion operators:

If a user-defined conversion can give rise to exceptions (for example, because the source argument is out of range) or loss of information (such as discarding high-order bits), then that conversion should be defined as an explicit conversion.

Also, from MSDN: implicit (C# Reference):

In general, implicit conversion operators should never throw exceptions and never lose information so that they can be used safely without the programmer's awareness. If a conversion operator cannot meet those criteria, it should be marked explicit.

Considering this, your operator PositiveDouble(double d) should not be marked implicit, as Volume v = -1 will throw an exception.

So to answer your question:

Is explicit always necessary in potentially exceptional code?

No, it's not necessary, but it should.

Bordering on opinion-based: if your code is the only code using this conversion, and you find implicit conversion easier to read and/or maintain, feel free to use that.

As for

How does it protect the user?

See MSDN: explicit (C# Reference) mentions:

If a conversion operation can cause exceptions or lose information, you should mark it explicit. This prevents the compiler from silently invoking the conversion operation with possibly unforeseen consequences.

I can't really fathom when this would occur, but again, if you think you never convert from a negative double in your code anywhere, this should not ever throw.



Related Topics



Leave a reply



Submit