Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple conversion functions as "operator auto" in class

In the following code

struct S {
    operator auto() { return 42; }
};

operator auto is equivalent to operator int since actual type would be deduced from the literal 42 and that type is int. If I write 42.5 instead of 42 then operator auto would be interpreted as operator double for obvious reason. But when I use both at the same time I got a compiler error for all three major compilers (gcc, clang, msvc):

struct S {
    operator auto() { return 42; }
    operator auto() { return 42.5; }
};

Actual error messages are vary among compilers, but the reason is the same: "Function already defined".

I can't find in standard why the both operator auto (with different return type) can't be used simultaneously in one class. Could someone point me to the standard's clause where that set of conversion functions considered as forbidden?

like image 971
αλεχολυτ Avatar asked May 15 '21 20:05

αλεχολυτ


2 Answers

If you need just two or three operator autos in a class, then the trick with const and decltype(auto) will work for you:

#include <iostream>

struct S 
{
    operator auto() { return 42; }
    operator const auto() { return 42.5; }
    operator decltype(auto)() { return 43.5f; }
};

int main()
{
   S s;
   std::cout << (int)s << '\n';
   std::cout << (double)s << '\n';
   std::cout << (float)s << '\n';
}

https://gcc.godbolt.org/z/hvbesaM4z

Unfortunately, it does not work for more than three distinct operators. It is the limitation of the current C++.

like image 109
Fedor Avatar answered Oct 10 '22 13:10

Fedor


Based on idea from Fedor's answer you can even use at least 12 auto like operators with different qualifiers:

#include <iostream>

struct S {
    operator auto() { return 42; }
    operator auto() const { return '+'; }
    operator auto() volatile { return 44LL; }
    operator const auto() { return 45.5; }
    operator const auto() const { return 46.5f; }
    operator const auto() volatile { return 47L; }    
    operator volatile auto() { return 48ULL; }
    operator volatile auto() const { return 49U; }
    operator volatile auto() volatile { return 50UL; }
    operator decltype(auto)() { return 51.5L; }
    operator decltype(auto)() const { return 52.5L; }
    operator decltype(auto)() volatile { return 53.5L; }
};

int main() {
    const S s;
    std::cout << (int)(S)s << "\n";
    std::cout << (char)s << "\n";
    std::cout << (long long)(volatile S)s << "\n";
    
    std::cout << (double)(S)s << "\n";
    std::cout << (float)s << "\n";
    std::cout << (long)(volatile S)s << "\n";
    
    std::cout << (unsigned long long)(S)s << "\n";
    std::cout << (unsigned)s << "\n";
    std::cout << (unsigned long)(volatile S)s << "\n";
    
    std::cout << (long double)(S)s << "\n";
    std::cout << (long double)s << "\n";
    std::cout << (long double)(volatile S)s << "\n";
}
like image 38
αλεχολυτ Avatar answered Oct 10 '22 13:10

αλεχολυτ