Как использовать прокси-класс и шаблон для «имитации» перегрузки функции возвращаемым значением? - PullRequest
2 голосов
/ 05 марта 2020

Я попытаюсь углубиться в знания системы шаблонов и типов c ++, я знаю, что при перегрузке Type.Operator () он будет «перегружен» типом возвращаемого значения,

#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 ожидается, что должен быть какой-то способ заставить следующие строки работать по-разному в зависимости от типа возвращаемого значения:

int i = m.get();
short s = m.get();

Как это реализовать? Большое спасибо.

Ответы [ 3 ]

3 голосов
/ 05 марта 2020

... чтобы "имитировать" перегрузку функции по возвращаемому значению?

Игнорируя весь шаблон вашего примера и сосредоточившись исключительно на этом вопросе, вы можете определить первичную функцию шаблона с удаленным (основным шаблоном) определением и добавить явные (полные) специализации этой функции только для типов, для которых вы хотите иметь «перегрузку»:

#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
}

Обратите внимание, однако что вам нужно явно указать тип параметра шаблона одного типа, поскольку для вывода аргумента шаблона для работы не существует аргумента get().

1 голос
/ 05 марта 2020

Если я понимаю вашу цель, то в вашей реализации отсутствует (среди других необходимых исправлений) функция-член My, которая фактически возвращает Proxy.

Что-то вроде следующего (тестируемый здесь )

#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';
}
1 голос
/ 05 марта 2020

Вы можете использовать SFINAE как:

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();
}

Затем в классе Proxy вызовите вышеуказанные функции, такие как:

operator int() const {
    return myOwner->get<int>();
}
operator short() const {
    return myOwner->get<short>();
}

и в основной функции:

int i = m.get<int>();
short s = m.get<short>();

Демо

ПРИМЕЧАНИЕ : тот факт, что возвращаемое значение функции присваивается int или short, не используется в параметре шаблона вычет.

...