Концепции C ++ видят функцию для моего типа, но не видят ее для std :: vector - PullRequest
2 голосов
/ 08 июня 2019

Я пытаюсь реализовать что-то вроде Haskell Prelude в C ++ с помощью классов типов, таких как Functor, Monoid и так далее.Поэтому я решил использовать C ++ Concepts для проверки типов, но столкнулся с проблемой при попытке реализовать концепцию полугруппы.

Проблема возникает, когда я пытаюсь объявить концепцию, которая использует некоторую объявленную функциюи перегружен для необходимых типов позже в коде, но это актуально только для некоторых типов, таких как std :: vector, но для моих собственных типов работает хорошо.

Полный код:

template<class T>
struct S {
    // ...
};

template<class T>
concept Addable = requires(T a, T b) {
    { add(a, b) } -> T;
};

template<class T>
S<T> add(const S<T> & a, const S<T> & b) {
    // ...
    return {};
}

template<class T>
std::vector<T> add(const std::vector<T> & a, const std::vector<T> & b) {
    // ...
    return {};
}

int main() {
    std::cout << Addable<S<int>> << '\n';
    std::cout << Addable<std::vector<int>> << '\n';
}

Iожидаем вывод 1 1, но фактический вывод 1 0.Таким образом, он не распознает std :: vector как Addable независимо от объявленной перегрузки add (std :: vector), но распознает тип S как Addable.

UPD: Проблема исчезнет, ​​если я переместу функцию add, чтобы перейти к концепции Addable.Но выглядит очень неудобно и неясно, что мне нужно реализовать все концепции, которые я включаю, для таких типов, как std::vector, прежде чем включать эти концепции.

UPD2: Я использую GCC 9.1.0.

1 Ответ

1 голос
/ 09 июня 2019

Я думаю, что это недостаток в этой экспериментальной реализации концепции Clang. [temp.concept] / 8 говорит:

Концепция не реализована ([temp.spec]).

См. Также: В каком контексте контроля доступа оцениваются концепции?

Это означает, что разрешение имен, как оно описано в [temp.res] , не применяется к выражению, являющемуся определением понятия. Если нужно было создать экземпляры концептов, то функция add не могла бы быть найдена при поиске безоговорочного имени. Вот почему Clang выдает ошибку.

Согласно стандарту, когда id-выражение называет концепцию, нормализованное выражение-ограничение оценивается там, где появляется id-выражение ( [expr.prim.id] / 4 ).

Менее формально, выражение, являющееся определением понятия, оценивается в контексте выражения, которое называет понятие. Таким образом, Addable<vector<int>> должно быть истинным, потому что в контексте этого выражения, add может быть найдено путем поиска без определения имени.

...