Невозможно определить тип заполнителя в концепции - PullRequest
3 голосов
/ 16 марта 2019

Я пытаюсь реплицировать стандартные концепции C ++ 20, используя Concepts TS в GCC 8, чтобы я мог использовать их, прежде чем они будут доступны в стандартной библиотеке.Я в основном копировал и вставлял все из последнего черновика, и я столкнулся с проблемой:

#include <type_traits>
#include <utility>

// [concept.same]
template <typename T, typename U>
concept bool Same = std::is_same_v<T, U>;

// [concept.assignable]

// TODO: Proper implementation requires std::common_reference that is not in
// libstdc++ yet and implementing it myself is too hard.
template <typename LHS, typename RHS>
concept bool Assignable = std::is_lvalue_reference_v<LHS> &&
    requires(LHS lhs, RHS&& rhs)
    {
        {lhs = std::forward<RHS>(rhs)} -> Same<LHS>;
    };

template <typename T>
    requires Assignable<T&, T>
void Test(T a) {}

int main()
{
    Test(42);
}

Многие другие концепции требуют присваиваемых типов, и при попытке использовать эту концепцию я получаю:

Concepts.h:54:14: note: within 'template<class LHS, class RHS> concept const bool ftz::General::Assignable<LHS, RHS> [with LHS = int&; RHS = int]'
 concept bool Assignable = std::is_lvalue_reference_v<LHS> &&
              ^~~~~~~~~~
Concepts.h:54:14: note:     with 'int& lhs'
Concepts.h:54:14: note:     with 'int&& rhs'
Concepts.h:54:14: note: unable to deduce placeholder type 'ftz::General::Same<int&>' from 'lhs =(forward<int>)(rhs)'

В чем здесь проблема?

1 Ответ

4 голосов
/ 17 марта 2019

Это было недавнее изменение, внесенное в Концепции, которое было принято в Сан-Диего (ноябрь 2018 г.) в результате P1084 . Проблема в том, что раньше это было:

{ E } -> Same<T>;

Фактически означало, что выражение f(E) действительно для придуманного шаблона функции вида:

template <class U> requires Same<U, T> void f(U );

Что, очевидно, никогда не сохранится для ссылочных типов T (как в OP).

Другими словами, старое правило гласило: { E } -> Same<T> означало Same<remove_cvref_t<decltype((E))>, T>. Новое правило состоит в том, что это означает Same<decltype((E)), T>. Похоже, что ни gcc -fconcepts, ни ветвь концептов clang пока не реализуют эти новые правила.

<ч />

Текущий обходной путь должен измениться:

{ E } -> Same<LHS> // i.e. Same<T&>

до:

{ E } -> Same<std::remove_reference_t<LHS>>& // i.e. Same<T>&
...