Use Explicit Conversion Functions to Avert Reckless Implicit Conversions

he compiler invokes user-defined conversion functions (which are also called conversion operators) implicitly. In most cases, this process is well-behaved and intended. However, there are cases when you certainly don’t want the compiler to invoke the conversion operator implicitly—but you can’t prevent it. Several workarounds have been devised to mitigate this problem, including the indirect conversion idiom. And yet, these workarounds are neither intuitive nor perfect. C++0x finally brings a radical solution in the form of explicit conversion functions.

Your class defines a conversion function to a certain type. You want to ensure that this function will be invoked only when appropriate.

Declare conversion functions explicit, thus forcing clients to use casts explicitly.

Presenting the Problem
The problematic nature of unrestrained conversion functions is clearly demonstrated in smart pointers. Class std::shared_ptr defines an implicit conversion to an implementation-defined Boolean type. As you may recall, the “implementation-defined Boolean type” is actually a pointer to a data member, not the built-in booltype:

template class Ptr{private: struct PtrConversion {  int valid; };public: operator PtrConversion::*pmi() const//Boolean conversion {  return rawptr? &PtrConversion::valid : 0; }};

As ugly as this kludge may seem, it does prevent awful bugs like these:

Ptr p1, p2;cout<<"p1 + p2 = "<< p1+p2 < pf;Ptr  pq; //Query and File are unrelated typesif(pf==pq)... //compares raw pointers, not objects!

There are, however, other ailments that the indirect conversion idiom cannot cure.

Ambiguity Issues
Suppose you’re designing a simple string class. Naturally, your class defines a conversion functions to char * and an overloaded [] operator. Each of these functions has a const and a non-constversion:

class BuggyString { char buf[100];public: BuggyString(const char* s); //subscripting char& operator[] (size_t n); const char& operator[] (size_t n) const;//implicit conversion to char* operator char* (); operator const char* () const;};

When some compilers compile the following code, they issue a compilation error:

BuggyString str("buggi");str[4] = 'y'; //error, overload resolution ambiguity

Where does this error come from? When the compiler sees the expression str[4], it looks up the definition of str and discovers that str isn’t an array. At this stage, there are two possible ways to interpret the expression str[4]:

  • Invoking the overloaded [] member function.
  • Invoking BuggyString::operator char *, and then applying the built-in [] operator to the result.

In other words, depending on the underlying type of std::ptrdiff_t (which affects overload resolution) the compiler is faced with two options: either interpret str[4]as:

str.operator[](4) //call overloaded []

or interpret it as:

str.operator char*()[4]//call operator char* +built-in []

In C++03, the common approach is to avoid conversion functions in the first place. The std::string class, for example, defines the member function string::c_str() as a substitute for operator const char *. This approach works well when the destination type is known at compile time. However, when templates are involved, named functions are problematic because the destination type can only be determined when you instantiate a template.

Explicit Conversion Functions
You’re already familiar with the use of explicit in constructors that take a single argument. Unless declared explicit, a constructor C(arg) operates as implicit conversion functions that converts arg to C. C++0x extends the use of explicit to conversion functions as well. When you declare a conversion function as explicit, implicit conversions are permitted only in direct initialization expressions:

class BuggyString {//now explicit explicit operator char*(); explicit operator const char* () const;};const char * ps(str);//OK, direct initialization ps=str; //Error, explicit cast requiredps=(const char *) str; //OK, C-style cast ps=static_cast(str); //OK, new style cast

Safe and Sound
The use of explicitguarantees that conversion functions do not surprise you with undesirable conversions. Instead, every conversion operation requires an explicit permission from you in the form of at cast notation (except in the case of direct initializations). Explicit conversion functions thus offer a safe and uniform method for conversions.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin


The Latest

homes in the real estate industry

Exploring the Latest Tech Trends Impacting the Real Estate Industry

The real estate industry is changing thanks to the newest technological advancements. These new developments — from blockchain and AI to virtual reality and 3D printing — are poised to change how we buy and sell homes. Real estate brokers, buyers, sellers, wholesale real estate professionals, fix and flippers, and beyond may

man on floor with data

DevX Quick Guide to Data Ingestion

One of the biggest trends of the 21st century is the massive surge in internet usage. With major innovations such as smart technology, social media, and online shopping sites, the internet has become an essential part of everyday life for a large portion of the population. Due to this internet

payment via phone

7 Ways Technology Has Changed Traditional Payments

In today’s digital world, technology has changed how we make payments. From contactless cards to mobile wallets, it’s now easier to pay for goods and services without carrying cash or using a checkbook. This article will look at seven of the most significant ways technology has transformed traditional payment methods.