Reputation: 8087
I'll trying to dig into more c++ template and type system knowledge, I know that by overloading Type.Operator(), it will seem to "overload" by return type,
#include<iostream>
using namespace std;
class My{
int getInt() const {return 20;}
short getShort() const {return 3;}
public:
template<class T>
T get() const
template<int>
int get() const {return getInt();}
template<short>
short get() const {return getShort();}
};
struct Proxy{
My const* myOwner;
Proxy(My const* owner):myOwner(owner){}
operator int() const {return myOwner->getInt();}
operator short() const {return myOwner->getShort();}
};
int main(){
My m;
Proxy p(&m);
int _i = p;//works!
short _s = p;//works!
cout<<_i<<","<<_s<<",\n";
// How to use template My::get
int i = m.get(); // doesn't compile
short s = m.get(); // doesn't compile
cout<<i<<","<<s<<",\n";
return 0;
}
I expect there should be some way to make the following lines work to differ function call according to return type:
int i = m.get();
short s = m.get();
How to implement this? Thanks a lot.
Upvotes: 2
Views: 594
Reputation: 12799
If I understand your goal, what's missing in your implementation (among other necessary fixes) is member function of My
which actually returns a Proxy
.
Something like the following (testable here)
#include<iostream>
class Proxy;
class My
{
public:
template<class T = Proxy> // <--
T get() const;
};
class Proxy
{
My const& owner_;
public:
Proxy(My const& owner) : owner_(owner)
{}
operator int() const;
operator short() const;
};
template<>
Proxy My::get<Proxy>() const {
return *this; // <---
}
template<>
int My::get<int>() const {
return 20;
}
template<>
short My::get<short>() const {
return -3;
}
Proxy::operator int() const {
return owner_.get<int>();
}
Proxy::operator short() const {
return owner_.get<short>();
}
int main()
{
My m;
int i = m.get<int>();
short s = m.get<short>();
std::cout << i << ", " << s << '\n';
int i_ = m.get();
short s_ = m.get();
std::cout << i_ << ", " << s_ << '\n';
}
Upvotes: 1
Reputation: 12293
You can use SFINAE like:
template <typename T,
typename std::enable_if<std::is_same<T, int>::value>::type* = nullptr>
int get() const {
return getInt();
}
template <typename T,
typename std::enable_if<std::is_same<T, short>::value>::type* = nullptr>
short get() const {
return getShort();
}
Then in Proxy
class call the above functions like:
operator int() const {
return myOwner->get<int>();
}
operator short() const {
return myOwner->get<short>();
}
and in main function:
int i = m.get<int>();
short s = m.get<short>();
NOTE: The fact that the function return value is being assigned to an int
or short
isn't used in template parameter deduction.
Upvotes: 1
Reputation: 73236
... to "simulate" function overload by return value?
Ignoring all the boilerplate of your example and focusing solely on this question, you could define a primary template function with a deleted (primary template) definition, and add explicit (full) specializations of this function only for the types for which you want to have an "overload":
#include <cstdint>
template <typename T>
T get() = delete;
template<>
uint8_t get<uint8_t>() { return 42U; } // or delegate to getUint8().
template<>
uint32_t get<uint32_t>() { return 43U; }
template<>
float get<float>() { return 44.5F; }
int main() {
const auto a = get<uint8_t>();
const auto b = get<uint32_t>();
const auto c = get<float>();
// const auto d = get<uint16_t>(); // error: use of deleted function
}
Note however that you need to explicitly specify the type of the single type template parameter, as there is no argument of get()
for template argument deduction to work with.
Upvotes: 3