Question

The following example contains two templated classes to represent degrees and radians with an explicit conversion operator to cast between them. It compiles and runs with g++ (ideone link) but not with Visual Studio 2013 with Visual C++ Compiler Nov 2013 CTP (CTP_Nov2013) as the platform toolset.

#include <iostream>

static const double PI = 3.14159265358979323846;

// Forward declarations
template< typename T > class radians;
template< typename T > class degrees;

template< typename T >
class degrees
{
    public:
        degrees(const T value)
            : value_(value)
        {}

        template< typename U >
        explicit operator U() const
        {
            return value_ * PI / 180.0;
        }

        T value() const { return value_; }

    private:
        T value_;
};

template< typename T >
class radians
{
    public:
        radians(const T value)
            : value_(value)
        {}

        template< typename U >
        explicit operator U() const
        {
            return (value_* 180.0) / PI;
        }

        T value() const { return value_; }

    private:
        T value_;
};

template< typename T >
std::ostream& operator<<(std::ostream& out, const radians<T>& r)
{
    return out << r.value() << "r";
}

template< typename T >
std::ostream& operator<<(std::ostream& out, const degrees<T>& r)
{
    return out << r.value() << "d";
}


int main()
{
    using degs = degrees<float>;
    using rads = radians<float>;

    auto d = degs{10};
    auto r = static_cast<rads>(d);

    std::cout << d << std::endl;
    std::cout << r << std::endl;

    return 0;
}

The Visual Studio error output:

error C2440: 'static_cast' : cannot convert from 'degrees<float>' to 'rads' degrad.cpp  69  1   degrad
error C3536: 'r': cannot be used before it is initialized   degrad.cpp  72  1   degrad

What's wrong? Why does it work with g++ but not Visual Studio 2013? Which compiler is doing the right thing?

Was it helpful?

Solution

A compiler not accepting the metioned snippet is faulty, the code provided is legal and should not yield a fatal diagnostic during compilation. In other words; msvc is doing it wrong.


RELEVANT SECTIONS OF THE STANDARD

12.3.2 Conversion functions [class.conv.fct]

2 A function may be explicit (7.1.2), in which case it is only considered as a user-defined conversion for direct-initialization (8.5). Otherwise, user-defined conversions are not restricted to use in assignments and initializations.

8.5 Initializers [dcl.init]

16 The initialization that occurs in the forms

T x (a);
T x {a};

as well as in new expressions (5.3.4), static_cast expressions (5.2.9), functional notation type conversions (5.2.3), and base and member initializers (12.6.2) is called direct-initialization.


HOW WOULD I WORK AROUND MSVC++ BEING FAULTY?

  • use typedef radians<float> rads; instead of using, and either;

    • remove explicit from your conversion function, or;

    • initialize your variable using auto r = rads { d } or auto r = rads (d);.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top