Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check for function existance on other type using C++ concepts

Does anybody know how to make a C++ concept T such that the function g is only defined for arguments t with type T if there exist an overload of f in B that accepts an argument t?

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

As an example, I want to define a to_string for everything that std::stringstream accepts, and define something like

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

All examples on concepts deal with the easier case of requiring the existance of a function on a type, while in this case we want to check existance of a function on another type.

like image 822
Carucel Avatar asked Apr 24 '20 10:04

Carucel


2 Answers

If you want to check if the type is streamable or not, you can have something like:

#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; 
}

Demo

like image 87
NutCracker Avatar answered Nov 14 '22 14:11

NutCracker


You can use two different type placeholders in a single concept, to require both the existence of a member function for an instance of one of the type placeholders, as well as the argument to said member function to match the type of another placeholder. E.g.:

#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
}
like image 22
dfrib Avatar answered Nov 14 '22 16:11

dfrib