【问题标题】:Dectecting template methods with SFINAE使用 SFINAE 检测模板方法
【发布时间】:2018-10-14 17:36:17
【问题描述】:

我有一个简单的特征struct hasMemberSerialize,我试图用它来确定任何给定的类是否与callSerialize() 兼容。 struct 看起来像这样:

template<typename Type, typename ArchiveType>
struct hasMemberSerialize {
    template<typename T, typename A>
    static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type);

    template<typename, typename>
    static std::false_type test(...);

    static const bool value = std::is_same<decltype(test<Type, ArchiveType>(0)), std::true_type>::value;
};

这编译并运行良好,但是,我的hasMemberSerialize::value 总是 std::false_type。我使用了类似的方法来检查非模板方法;但是,我正在检查的 callSerialize() 方法看起来像:

template<typename Archive, typename Type>
static auto callSerialize(Archive& a, Type& t) -> decltype(t.serialize(a)) {
    // Implementation
}

我使用std::cout 做了一些测试,如下所示:

Serialization::access::callSerialize(JSON, myType);

std::cout << std::boolalpha
    << hasMemberSerialize<MyType, JSONOutputArchive>::value << std::endl;

方法调用callSerialize(JSON, myType)按预期工作并序列化类型;但是,hasMemberSerialize::value 打印出false。最后,myType 是一个简单的测试类:

class MyType {
    int myInt;

public:
    MyType() : myInt(4) {}

    template<typename Archive>
    void serialize(Archive& a) {
        a(myInt);
    }
};

...

MyType myType;

【问题讨论】:

  • 离题建议:你可以把static constexpr bool,而不是简单的static const bool,变成value里面的hasMemberSerialize

标签: c++ c++11 templates sfinae decltype


【解决方案1】:

我犯了一个很简单的错误,一行

static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type);

需要

static auto test(int) -> decltype(Serialization::access::callSerialize(std::declval<A&>(), std::declval<T&>()), std::true_type{});

注意:std::true_type 后面的大括号。

正如 Max66 在他的评论中解释的那样:

重点是decltype()返回一个对象的类型;所以decltype(3)int;当您写decltype(std::true_type)(即decltype(int))时,您会询问类型的类型;您必须询问std::true_type 类型的对象的类型,即decltype(std::true_type{}) 或(更好,恕我直言)decltype(std::declval&lt;std::true_type&gt;())

【讨论】:

  • 这很奇怪,可能是因为它没有 default 构造函数作为 integral_constant。因此它需要一个花括号列表构造函数。此外,回答您自己的问题做得很好,但也许将其添加为您的问题的编辑可能会更好?我不确定。
  • “我不知道这有什么不同”——关键是decltype()返回了一个对象的类型;所以decltype(3)int;当您写decltype(std::true_type)(即decltype(int))时,您会询问类型的类型;您必须询问std::true_type 类型的对象 的类型,即decltype(std::true_type{}) 或(更好,恕我直言)decltype(std::declval&lt;std::true_type&gt;())
  • 我明白了,如果你写了一个答案来解释说真的很快我就可以接受它是正确的!
  • 完成。题外话建议:当您撰写针对与答案(或问题)作者不同的特定人的评论时,请以@&lt;name&gt;开头;这样人就会收到信号。
【解决方案2】:

正如您所发现的,问题是您必须在 decltype() 的末尾使用带有大括号的 std::true_type{}

所以

decltype( <other elements>, std::true_type )

是错误的,并给出一个错误,其中

decltype( <other elements>, std::true_type{} )
// .......................................^^

有效。

重点是decltype() 返回给定实体的类型(变量、常量等)或该类型的表达式;所以(通过例子)给定decltype(3),你会得到int

如果你写

decltype( std::true_type )

你要求一个类型的类型,这是错误的。

如果你写

decltype( std::true_type{} )

您询问std::true_type 类型的元素(std::true_type{})的类型;这是正确的,你会得到std::true_type

我建议另一种方式:

decltype( std::declval<std::true_type>() )

其中std::declval() 是标准模板函数(仅声明,但对于返回接收到的模板类型的元素的decltype() 来说已经足够了。

所以std::declval&lt;std::true_type&gt;()std::true_type 类型的表达式,decltype() 显然返回std::true_type

在默认可构造类型的情况下,您可以创建该类型的实体,只需在类型名称的末尾添加几个大括号即可。但是当一个类型不是默认可构造的时,你无法解决这个原因。

使用std::declval(),即使该类型不是默认可构造的,您也可以获得给定类型的表达式。

如果是std::true_type,您可以通过两种方式解决,但我建议无论如何都使用std::declval()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    相关资源
    最近更新 更多