0

В следующем коде я хотел добиться эффекта бинарной цепочки операторов для конкретного определения типа, которое я хочу использовать, - для тривиальной цепочки операторов бинарный оператор возвращает тот же тип объекта, в большинстве случаев просто возвращается *this, который можно было бы тривиально использовать снова, чтобы связать следующий объект того же типа.Оператор-оператор с ++ 11/14 с перегрузкой параметра шаблона шаблона

Однако в моем случае двоичные операторы принимают в качестве входных данных два reference_wrappers двух одинаковых введенных объектов (awaitable<T>::ref) и возвращают агрегированный объект типа (awaitable<awaitable<T>::ref>), и я хотел использовать возвращаемый агрегированный объект для связывания затем awaitable<T>::ref и снова верните следующий агрегированный объект типа awaitable<awaitable<T>::ref> - обратите внимание, что возвращаемый объект всегда является одним и тем же типом awaitable<awaitable<T>::ref>, независимо от того, сколько еще цепочек происходит.

Оператор friend с параметром шаблона шаблона, определенным в местоположении (XXX), надеется служить для этой цели, но компиляторы, похоже, не желают выполнять привязку.

Может ли кто-нибудь пролить свет на то, как я могу достичь результата, как описано?

Спасибо!

#include <functional> 

template <typename T> 
struct awaitable 
{ 
    typedef std::reference_wrapper<awaitable> ref; 

    // (A) - okay 
    friend awaitable<ref> operator||(ref a1, ref a2) 
    { 
     awaitable<ref> r; 
     return r; 
    } 

    // (XXX) - this doesn't bind 
    template < template <typename> class _awaitable > 
    friend awaitable<ref> operator||(typename awaitable<typename _awaitable<T>::ref>::ref a1, ref a2) 
    { 
     awaitable<ref> r; 
     return r; 
    } 
}; 

int main(int argc, const char * argv[]) 
{ 
    awaitable<void> a1; 
    awaitable<void> a2; 
    auto r1 = a1 || a2; // Okay - r1 is of type awaitable<awaitable<void>::ref> 

    awaitable<void> a3; 
    auto r3 = r1 || a3; // doesn't bind to the operator defined at XXX 

    return 0; 
} 

[EDIT] -

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

+0

Извините за правки, я пытался упростить код и устранить любые возможные недоразумения как можно больше, и, надеюсь, код, указанный выше, должен быть очень прост для чтения (без прокрутки вниз!) – Dejavu

+0

Примечание: входные объекты завершены wrap_wrapper, я специально не хочу, чтобы происходило копирование, и в реальном коде конструктор копирования удаляется – Dejavu

ответ

0

кажется, что функция друг с параметром шаблона шаблон делает шаблон вычет из строя. Решение состоит в том, чтобы удалить параметр шаблона шаблона, и расширение :: реф использования в StD :: reference_wrapper в определении друга функции:

#include <functional> 

template <typename T> 
struct awaitable 
{ 
    typedef std::reference_wrapper<awaitable> ref; 

    // (A) - okay 
    friend awaitable<ref> operator||(ref a1, ref a2) 
    { 
     awaitable<ref> r; 
     return r; 
    } 

    // (XXX) - removing the template template parameter makes the template instantiation for a specific type T to generate a namespace version of the function! 
    friend awaitable<ref> operator||(std::reference_wrapper<awaitable<std::reference_wrapper<awaitable<T>>>> a1, ref a2) 
    { 
     awaitable<ref> r; 
     return r; 
    } 
}; 

// template <typename T> 
// awaitable<typename awaitable<T>::ref> operator||(typename awaitable<typename awaitable<T>::ref>::ref a1, typename awaitable<T>::ref a2) 
// { 
//  awaitable<typename awaitable<T>::ref> r; 
//  return r; 
// } 

int main(int argc, const char * argv[]) 
{ 
    awaitable<void> a1; 
    awaitable<void> a2; 
    auto r1 = a1 || a2; // Okay - r1 is of type awaitable<awaitable<void>::ref> 

    awaitable<void> a3; 
    auto r3 = r1 || a3; // now it works! 

    return 0; 
} 

Демо here

0

это то, что вам нужно?

template < template <typename> class _awaitable, typename U > 
friend auto operator||(_awaitable<std::reference_wrapper<U>> a1, ref a2) 
{ 
    awaitable<ref> r; 
    return r; 
} 

live demo

EDIT1

Я видел ваш ответ, где вы удалили параметр шаблона, чтобы заставить его работать. Это отлично работает, если void является единственным типом, который вы используете. Если вы попытаетесь использовать другой тип, это не удастся. Самое близкое, что мне нужно обойти, - это экспликация с использованием std :: ref (r1), например.

template<typename U> 
friend awaitable<ref> operator||(std::reference_wrapper<awaitable<std::reference_wrapper<awaitable<U>>>> a1, ref a2) 
{ 
    std::cout << "(XXX2)" << std::endl; 
    awaitable<ref> r; 
    return r; 
} 

awaitable<int> a4; 
auto r4 = std::ref(r1) || a4; 

live demo 2

+0

Нет. Вам не хватает :: ref после _awaitable, см. это: http: //coliru.stacked-crooked.com/a/ed848c7f0098741d – Dejavu

+0

, но это не то, что вы или вы, вы вызываете r1 || a3 -> awaitable >> || awaitable

+0

Я хочу, чтобы объект был неявно преобразован в версию ref, с которой работало первое определение, и мне интересно, почему XXX не – Dejavu

Смежные вопросы