Проверка существования функции в другом типе с использованием концепций C ++ - PullRequest
4 голосов
/ 24 апреля 2020

Кто-нибудь знает, как сделать концепцию C ++ T такой, чтобы функция g определялась только для аргументов t с типом T, если существует перегрузка f в B, которая принимает аргумент t?

struct A1 {};
struct A2 {};
struct B {
    void f(A1 a1) {}
};
void g(T t) {
    B b;
    b.f(t);
}

В качестве примера я хочу определить to_string для всего, что принимает std::stringstream, и определить что-то вроде

std::string to_string(T t) {
    std::stringstream ret;
    ret << t;
    return ret.str();
}

Все примеры В концепциях рассматривается более простой случай, когда требуется наличие функции для типа, в то время как в этом случае мы хотим проверить существование функции для другого типа.

Ответы [ 2 ]

5 голосов
/ 24 апреля 2020

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

#include <iostream>
#include <concepts>
#include <sstream>

template <typename T> 
concept Streamable = requires (T x, std::ostream &os) { os << x; };

struct Foo {};
struct Bar {};

std::ostream& operator<<(std::ostream& os, Foo const& obj) {
    // write obj to stream
    return os;
}

template <Streamable T>
std::string to_string(T t) {
    std::stringstream ret;
    ret << t;
    return ret.str();
}

int main() {
    Foo f;
    Bar b;

    to_string(f);
    to_string(b); // error

    return 0; 
}

Демо

2 голосов
/ 24 апреля 2020

Вы можете использовать два разных типа заполнителей в одной концепции, чтобы требовать как наличия функции-члена для экземпляра одного из заполнителей типа, так и аргумента указанной функции-члена для соответствовать типу другого заполнителя. Например:

#include <iostream>

template<typename T, typename U>
concept HasMemFnConstFoo = requires(const T t, const U u) {
    t.foo(u);
};

template<typename U>
struct Bar {
    template <typename T>
    static void bar(const T& t)
    {
        if constexpr (HasMemFnConstFoo<T, U>) { t.foo(U{}); }
        else { std::cout << "foo() not defined\n"; }
    }
};

struct A1 {};
struct A2 {};
struct B1 {
    void foo(const A1&) const { std::cout << "B1::foo()\n"; }
};
struct B2 {
    void foo(const A1&) { std::cout << "B2::foo()\n"; }
};
struct B3 {
    void foo(A1&) const { std::cout << "B3::foo()\n"; }
};

int main() {
    Bar<A1>::bar(B1{});  // B1::foo()
    Bar<A2>::bar(B1{});  // foo() not defined
    Bar<A1>::bar(B2{});  // foo() not defined [note: method constness]
    Bar<A2>::bar(B2{});  // foo() not defined
    Bar<A1>::bar(B3{});  // foo() not defined [note: argument constness]
    Bar<A2>::bar(B3{});  // foo() not defined
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...