【问题标题】:Can you detect template member of a class using std::is_detected您可以使用 std::is_detected 检测类的模板成员吗
【发布时间】:2021-11-18 08:02:44
【问题描述】:

我使用std::experimental::is_detected 来确定类是否具有某些成员函数:

#include <utility>
#include <experimental/type_traits>

template<typename USC>
class Descriptor
{
private:

    template<class T>
    using has_member1_t = 
        decltype(std::declval<T>().member1(std::declval<std::vector<char> &>()));

public:

    static constexpr bool has_member1 = 
        std::experimental::is_detected_convertible_v<long long,
                                                     has_member1_t,
                                                     USC>;
};

问题是我还需要确定类是否具有某些具有以下签名的模板成员函数

template<typename Derived>
int member2(Eigen::ArrayBase<Derived> &&)

我试过这样做:

//Inside Descriptor

template<class T, class U>
using has_member2_t = 
    decltype(std::declval<T>().member2(std::declval<Eigen::ArrayBase<U> &&>()));

static constexpr bool has_member2 = 
    std::experimental::is_detected_convertible_v<long long,
                                                 has_member2_t,
                                                 USC>;

但它不起作用。由于我对 C++ TMP 并没有真正的经验,所以我想知道有没有办法使用 std::experimental::is_detected 或其他一些实用程序来实现这一点?

【问题讨论】:

  • c++20可以吗?这种代码在概念上是相当琐碎的。
  • @super 还可以,但有点不可取。
  • 添加了两种方法的示例。
  • @super 谢谢!

标签: c++ template-meta-programming


【解决方案1】:

如果 c++20 是一个选项,那么通过使用概念,这种代码已经变得更容易阅读和编写。

#include <iostream>
#include <vector>

struct Foo {
    int member1(int) {
        return 1;
    }

    template <typename T>
    double member2(std::vector<T>) {
        return 2.5;
    }
};

struct Bar {};

template <typename T>
concept MyConcept = requires (T t) {
    { t.member1(0) } -> std::same_as<int>;              // We can check return type
    { t.template member2<int>(std::vector<int>{}) };    // but we don't have to
};

int main() {
    static_assert(MyConcept<Foo>);
    static_assert(!MyConcept<Bar>);
}

您尝试的问题是您没有通过 U 的任何内容进行检查。我还将对其进行修改以使用.template member2&lt;...&gt; 语法来显式检查模板。

这是一个例子。

#include <iostream>
#include <vector>
#include <utility>
#include <experimental/type_traits>

struct Foo {
    int member1(int) {
        return 1;
    }

    template <typename T>
    double member2(std::vector<T>) {
        return 2.5;
    }
};

struct Bar {};

template<class T, class U>
using has_member2_t = 
    decltype(std::declval<T>().template member2<U>(std::declval<std::vector<U> &&>()));

int main() {
    static constexpr bool has_member2_Foo = 
    std::experimental::is_detected_convertible_v<long long,
                                                 has_member2_t,
                                                 Foo, double>;

    static constexpr bool has_member2_Bar = 
    std::experimental::is_detected_convertible_v<long long,
                                                 has_member2_t,
                                                 Bar, double>;

    static_assert(has_member2_Foo);
    static_assert(!has_member2_Bar);
}

【讨论】:

  • 注意它也匹配template&lt;typename UnrelatedType&gt; int member2(vector&lt;int&gt;)
  • @Jarod42 是的。我认为这是使用convertible 版本的is_detected 的重点。
  • 你错过了我的意思:格式良好的member2&lt;int&gt;(std::declval&lt;std::vector&lt;int&gt;&gt;()) 并不能保证member2&lt;double&gt;(std::declval&lt;std::vector&lt;double&gt;&gt;()) 是。我提供了一个反例。您的解决方案可能对 OP 来说已经足够好了。
  • 可能仍然没有抓住重点。这是一个模板。也许它适用于int 而不是double。好的。但那你的建议是什么?检查我们关心的所有实例?如果我们真的愿意,我认为这不是问题。
  • 我没有看到通用的方法,我怀疑是否存在。这也是一个奇怪的要求:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
相关资源
最近更新 更多