是否可以测试某些类型是否可以通过 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>::type
是 true_type
而TestValidBind<OneParamStruct>::toTypesOf<tmp>::type
是 false_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
) 是可变参数的。
更惯用的说法是 bool
从 false_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++,我不知道为什么会这样。但我们可以简化它,看看是否有帮助。我们实际上并不需要封闭的结构 TestValidBind
。 toTypesOf
如果我们移植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++。
如果您愿意,我们可以更进一步,将所有内容放入 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
,我们有一个更通用的解决方案,您可以轻松更改要用作附加类型的类型。
关于c++ - 使用 SFINAE 检查类型是否可以绑定(bind)到模板模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36411565/