Как переопределить обобщенную функцию для агентов `const T &` и `T &&`, где T может быть ссылкой? - PullRequest
2 голосов
/ 11 июня 2019

Я пытаюсь реализовать что-то вроде Rust типа Result<T,E> в C ++, который представляет собой объединение со значением T или E.

Некоторые из его конструкторов:

template <typename T, typename E>
Result<T,E>::Result(const T& value) : isOk(true), value(value) {}

template <typename T, typename E>
Result<T,E>::Result(T&& value) :  isOk(true), value(std::move(value)) {}

Он работает, как я ожидаю, для T и E, которые не являются ссылочными типами или указателями, но не компилируется, если какой-либо из базовых типов является ссылкой. Например:

MyType my_object;
Result<MyType&, AnyOtherType> result(my_object);

выдает следующую ошибку:

./result.h:46:5: error: multiple overloads of 'Result' instantiate to the same signature 'void (MyType &)'
    Result(T&& value);
    ^
main.cpp:39:23: note: in instantiation of template class 'Result<MyType &, int>' requested here
  Result<MyType&,int> result(object);
                      ^
./result.h:37:5: note: previous declaration is here
    Result(const T& value);
    ^

Я понимаю, что это из-за правил свертывания ссылок (& + && = &): если T равно MyType&, то T& и T&& оба равны MyType&, следовательно, эти два конструктора имеют здесь такая же подпись.

Но есть ли какой-нибудь хороший способ преодолеть это и позволить T быть ссылкой, но при этом иметь конструкторы const T& и T&&?

1 Ответ

2 голосов
/ 11 июня 2019

Вы можете использовать шаблонный конструктор со ссылкой для пересылки, чтобы охватить оба случая:

template<typename T>
struct Result {
    template<typename... S>
    Result(S&&... s) : t(std::forward<S>(s)...) {}

    T t;
};

int i;
Result<int&> r1(i);
Result<int> r2(i);

Документы по теме std::expected<R, E> предложения:

...