首页 > 解决方案 > 模板函数取决于类成员函数参数

问题描述

层次结构中有两种类型的对象,但它们都有我要调用的静态“查找”方法。第二个参数是对象的名称,第一个是容器。一些类有一个在“数据库”中搜索的 find 方法(即,这是第一个参数),一些类有一个在该数据库的子容器中搜索的 find 方法,它本身就是这个层次结构中的一个类.

我想创建一个模板函数(好吧,或者它的一个 SFINAE 集),它可以根据它所拥有的 find 方法的签名来做正确的事情。我试图避免我的基本默认实现的旧的懒惰、令人满意的策略,并且即使它们是相同的替代实现类型,也不得不为其他情况考虑特殊情况。

老实说,这种 SFINAE 的东西有点让我头疼。我见过处理“有成员”情况的例子,但我认为我没有找到处理“有这个成员签名”和“有其他成员签名”之间分支的例子。所以它是一种三态,我猜,虽然我们不一定会遇到这样的情况,即使用一个根本没有该成员函数的类进行调用。

class Db;
class Obj { /*...*/ Db* getDb(); /*...*/ };
class Guts : public Obj { /*...*/ };
class Db : public Obj { /*...*/ Guts* getGuts(); /*...*/ };
class ChildA : public Obj { static ChildA* find(Db* db, const std::string& name); /*...*/ };
class ChildB : public Obj { static ChildB* find(Guts* dbg, const std::string& name); /*...*/ };

template <typename T>
bool findByName(Db* db, const std::string& name, T*& ret);

有什么提示或建议吗?对已经涵盖此主题的任何引用?C++11 版本更可取。

我认为我没有看到,并且很抱歉在这里需要手持的是如何使用与 SFINAE 相关的签名来表达 findByName 实现。我看到类似的问题,但我的小大脑无法在那里建立联系。;p

标签: c++sfinaemember-functions

解决方案


如果您使用这些find方法public,您可以像这样测试签名:

#include <utility>

template<class T, class... Signature>
struct has_find_signature {
    template<class> struct sfinae_true : std::true_type {};

    // fake functions, only to be used in SFINAE context
    template<class U>
    static auto test_find(int) -> // returns a sfinae_true<> if SFINAE succeeds
        sfinae_true<
            // std::declval<U>().  could be just  U::  since it's a static method 
            decltype( std::declval<U>().find( std::declval<Signature>()... ) )
        >;

    template<class U>
    static auto test_find(long) -> std::false_type;

    // decltype of a fake call to test_find() with an int to try the true_type (int)
    // version first and only fall back on the false_type (long) version if SFINAE fails.
    static constexpr bool value = decltype(test_find<T>(0))::value;
};

// Helper variable template (C++14 required):
template<class T, class... Signature>
constexpr bool has_find_signature_v = has_find_signature<T, Signature...>::value;

然后,您可以在其他模板或if constexpr情况下使用它。

这将1001在您的情况下打印:

std::cout
    << has_find_signature_v<ChildA, Db*, std::string>        // C++14
    << has_find_signature_v<ChildA, Guts*, std::string>      // C++14

    << has_find_signature<ChildB, Db*, std::string>::value   // C++11
    << has_find_signature<ChildB, Guts*, std::string>::value // C++11
;

推荐阅读