【问题标题】:Template function(s) which vary depending on class member function arguments根据类成员函数参数而变化的模板函数
【发布时间】:2020-10-27 17:37:08
【问题描述】:

层次结构中有两种类型的对象,但它们都有我想调用的静态“查找”方法。第二个参数是对象的名称,第一个是容器。一些类有一个在“数据库”中搜索的 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

【问题讨论】:

  • 您能否为您的案例显示(非模板)预期结果?我没有看到你的三态......
  • 也许我应该在回答之前要求澄清一下。 findByName 的第一个参数是 Db*。这是故意的还是应该是模板参数类型? TChild 类型之一吗?我希望看到与@Jarod42 要求的相同或至少一些伪代码,其中包含与findByName 一起使用的已定义类的实例。
  • JBaudhuin:你放弃这个问题了吗?我发现这个问题很有趣,如果我的电流不够,我想尝试提供更好的答案。你能提供更多信息吗?

标签: c++ sfinae member-functions


【解决方案1】:

如果您使用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
;

【讨论】:

    猜你喜欢
    • 2011-04-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多