Search code examples
c++castingoperator-overloadingsfinaeenable-if

enable_if on explicit templated cast operator gives "invalid static_cast"


I'm attempting to do a templated explicit cast operator. I found that notationally, you actually can put an expression with type traits and std::enable_if in the operator's "name" slot. But the following test doesn't give the desired behavior:

#include <iostream>
#include <type_traits>

class WillCast {
public:
    explicit operator int () {
       return 1020;
    }
};

class WontCast {
public:
    template <typename T>
    typename std::enable_if<
        std::is_same<T, int>::value, int
    >::type toInteger()
    {
       return 1324;
    }

    template <typename T>
    explicit operator typename std::enable_if<
        std::is_same<T, int>::value, int
    >::type ()
    {
       return 304;
    }
};

int main() {
    std::cout << static_cast<int>(WillCast{}) << "\n";   // ok
    std::cout << WontCast{}.toInteger<int>() << "\n";    // ok
    /* std::cout << static_cast<int>(WontCast{}); */     // error 
};

The error coming back from gcc 4.8.2 is:

test.cpp: In function ‘int main()’:
test.cpp:27:45: error: invalid static_cast from type ‘WontCast’ to type ‘int’
    std::cout << static_cast<int>(WontCast{});

If what I'm trying to do were not possible, I wouldn't be surprised. But it seems to think the syntax is all right, it's just not seeming to behave consistently between the "nearby" behaviors seen by WontCast::toInteger() and WillCast::operator int().

(This is a reduced example, of course my desired enable_if is trickier.)


UPDATE - "Sidebar intelligence(tm)" has thrown up How can I use std::enable_if in a conversion operator? which I didn't find through "BeforeYouAsked intelligence(tm)". I will look and see if it helps. Well, the solution used there doesn't seem to apply, because WontCast isn't a templated class. So not helping here.


Solution

  • If you move the enable_if part into the template, this works:

    template <typename T,
              typename = typename std::enable_if<std::is_same<T, int>::value>::type
              >
    explicit operator T()
    {
        return 304;
    }
    

    Given that:

    int i = static_cast<int>(WontCast{}); // ok
    double d = static_cast<double>(WontCast{}); // invalid static_cast