如果不存在,则调用自由函数而不是方法

Emi*_*lia 17 c++ templates c++11

假设您有一系列类型无关的类通过返回值的给定方法实现一个通用概念:

class A { public: int val() const { ... } };
class B { public: int val() const { ... } };
Run Code Online (Sandbox Code Playgroud)

假设您需要一个通用的自由函数,它T为任何未实现该val方法的类型返回一个常规值,或者val为所有具有一个类型的类型调用该方法:

template<class T> int val_of(const T& t) { return 0; }
template<class T> int val_of(const T& t) { return t.val(); }
Run Code Online (Sandbox Code Playgroud)

考虑A和B只是样本:您不知道将实现val多少类型,以及将不存在多少类型(因此显式特化不会扩展).

有没有一种基于C++标准的简单方法来静态选择val_of版本?

我正想着一个std::conditional或者std::enable_if,但我没有找到一种表达条件的简单方法.

0x4*_*2D2 16

您可以使用返回类型SFINAE:

template<typename T>
auto val_of(const T& t) -> decltype(std::declval<T>().val())
{
    return t.val();
}

int val_of(...)
{
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


use*_*917 5

稍长一点的评论...您的问题已得到解答。但是我最近有一个类似的问题。假设你想要写一个方法来打印字符串cout:使用成员函数write(std::cout),如果不提供免费使用的功能to_string(),如果没有可用的备用到operator<<。您可以像在答案中那样使用SFINAE表达式,并使用一个小类层次结构来消除重载的歧义:

struct S3 {};
struct S2 : S3 {};
struct S1 : S2 {};

template <class T>
auto print(S1, T const& t) -> decltype(t.write(std::cout)) {
    t.write(std::cout);
}

template <class T>
auto print(S2, T const& t) -> decltype(std::cout << to_string(t)) {
    std::cout << to_string(t);
}

template <class T>
void print(S3, T const& t) {
    std::cout << t;
}

template <class T>
void print(T const& t) {
    print(S1(), t);
}
Run Code Online (Sandbox Code Playgroud)