问题描述
层次结构中有两种类型的对象,但是它们都有一个我要调用的静态“查找”方法。第二个参数是对象的名称,第一个参数是容器。一些类具有在“数据库”中搜索的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
解决方法
如果您使用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,std::string>::value // C++11
<< has_find_signature<ChildB,std::string>::value // C++11
;