c++ - 使用 SFINAE 检查类型是否可以绑定(bind)到模板模板参数

标签 c++ templates c++11 metaprogramming

是否可以测试某些类型是否可以通过 SFINAE 绑定(bind)到模板模板参数?

我认为我尝试做的事情最好用以下示例代码来解释:

#include <iostream>

template<typename... T> using void_t = void;

template<typename T> struct TemporaryBindObject
{
    using type = TemporaryBindObject<T>;
};

template<template<typename...> class Dest> struct TestValidBind
{
    template<typename... Ts> struct toTypesOf
    {
        using type = std::false_type;
    };
    template<template<typename...> class Src, typename... Ts> struct toTypesOf<Src<Ts...>, void_t<Dest<Ts...,float>>>
    {
        using type = std::true_type;
    };
};

template<typename T> struct OneParamStruct{};
template<typename T1, typename T2> struct TwoParamStruct{};

int main()
{
    using tmp = TemporaryBindObject<int>;

    std::cout << "Can bind to TwoParamStruct: " << TestValidBind<TwoParamStruct>::toTypesOf<tmp>::type::value << std::endl;
    std::cout << "Can bind to OneParamStruct: " << TestValidBind<OneParamStruct>::toTypesOf<tmp>::type::value << std::endl;
}

首先我创建一个临时类型 tmp我想从中获取模板参数 int将其绑定(bind)到另一个类模板。 随着TestValidBind<template template type>::toTypesOf<typename>我想测试是否可以将给定类型的参数绑定(bind)到 template template parameter 并附加一个附加类型(示例中为 float)。

我想要的是TestValidBind<TwoParamStruct>::toTypesOf<tmp>::typetrue_typeTestValidBind<OneParamStruct>::toTypesOf<tmp>::typefalse_type .


代码示例无法使用 g++ -std=c++11 进行编译(5.3.1) 出现以下错误:

../test_SFINAE_with_template_binding.cc: In function ‘int main()’: ../test_SFINAE_with_template_binding.cc:34:96: error: ‘TestValidBind<OneParamStruct>::toTypesOf<TemporaryBindObject<int> >::type’ has not been declared

和报告false_type (这是错误的)如果OneParamStruct行被删除。

clang++ -std=c++11 (3.8.0) 代码编译但报告 false_type在这两种情况下。

这样的事情可能吗?


编辑:将附加类型从 void 更改为至float强调我想检查附加类型是否可能。

最佳答案

void_t技巧要求我们为主模板的参数之一指定默认类型 void 。您不需要主模板 ( toTypesOf ) 是可变参数的。

更惯用的说法是 boolfalse_type 继承的类型特征或true_type而不是嵌套 type 。不需要TemporaryBindObject有一个嵌套type .

TestValidBind应该看起来像这样:

template<template<typename...> class Dest> struct TestValidBind
{
    template<template<typename...> class Dest, typename T, typename = void_t<>> struct toTypesOf
        : std::false_type
    {};
    template<template<typename...> class Dest, template<typename...> class Src, typename... Ts> struct toTypesOf<Dest, Src<Ts...>, void_t<Dest<Ts..., float>>>
        : std::true_type
    {};
};

编辑:正如你所说,这不适用于 g++,我不知道为什么会这样。但我们可以简化它,看看是否有帮助。我们实际上并不需要封闭的结构 TestValidBindtoTypesOf如果我们移植Dest,模板可以在命名空间范围内参数传入:

template<template<typename...> class Dest, typename T, typename = void_t<>> struct toTypesOf
    : std::false_type
{};
template<template<typename...> class Dest, template<typename...> class Src, typename... Ts> struct toTypesOf<Dest, Src<Ts...>, void_t<Dest<Ts..., float>>>
    : std::true_type
{};

这适用于 g++。

DEMO

如果您愿意,我们可以更进一步,将所有内容放入 detail 中,使其更易于使用。命名空间并将其包装在别名模板中:

namespace detail
{
    template<typename... T> using void_t = void;

    template<typename... T> struct TemporaryBindObject {};

    template<template<typename...> class Dest, typename T, typename = void_t<>> struct toTypesOf
        : std::false_type {};
    template<template<typename...> class Dest, template<typename...> class Src, typename... Ts> struct toTypesOf<Dest, Src<Ts...>, void_t<Dest<Ts...>>>
        : std::true_type {};
}

template<template<typename...> class Dest, typename... Ts>
using IsValidBind = typename detail::toTypesOf<Dest, detail::TemporaryBindObject<Ts...>>;

template<template<typename...> class Dest, typename... Ts>
using IsValidBindWithFloat = IsValidBind<Dest, Ts..., float>;

template<template<typename...> class Dest, typename... Ts>
using IsValidBindWithVoid = IsValidBind<Dest, Ts..., void>;

std::cout << "Can bind to TwoParamStruct: " << IsValidBindWithFloat<TwoParamStruct, int>::value << std::endl;
std::cout << "Can bind to OneParamStruct: " << IsValidBindWithFloat<OneParamStruct, int>::value << std::endl;

现在我们不需要 using tmp ,我们有一个更通用的解决方案,您可以轻松更改要用作附加类型的类型。

DEMO

关于c++ - 使用 SFINAE 检查类型是否可以绑定(bind)到模板模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36411565/

相关文章:

c++ - 是否添加到 "char *"指针 UB,但它实际上并不指向 char 数组?

jquery - 使用JQuery通过id选择器从外部文件获取html内容

c++ - g++ 4.8.2 在列表方法参数默认初始化时出错

c++ - 解析数字字符串

c++ - 如何处理 CMake 中的子目录依赖关系?

c++ - 使用标准 :vector as low level buffer

c++ - 在类模板上使用 arm gcc 编译期间出现段错误

templates - joomla 管理模板未加载,如何手动更改?

C++ 访问尚未定义的模板参数成员

c++ - 内存泄漏线