xcv*_*cvr 6 c++ static-assert sfinae template-meta-programming c++14
更新
我发布了一份工作草案,rebind作为问题的答案.虽然我没有太多运气找到一种通用的方法来防止static_assert破坏元功能.
基本上我想检查是否T<U, Args...>可以从其他类型构造模板化类型T<V, Args...>.其中T和Args...是在这两种类型相同.问题是,T<>可能有一个static_assert完全打破我的元功能.
以下是我正在尝试做的粗略总结.
template<typename T>
struct fake_alloc {
using value_type = T;
};
template<typename T, typename Alloc = fake_alloc<T>>
struct fake_cont {
using value_type = T;
// comment the line below out, and it compiles, how can I get it to compile without commenting this out???
static_assert(std::is_same<value_type, typename Alloc::value_type>::value, "must be the same type");
};
template<typename T, typename U, typename = void>
struct sample_rebind {
using type = T;
};
template<template<typename...> class Container, typename T, typename U, typename... OtherArgs>
struct sample_rebind<
Container<T, OtherArgs...>,
U,
std::enable_if_t<
std::is_constructible<
Container<T, OtherArgs...>,
Container<U, OtherArgs...>
>::value
>
>
{
using type = Container<U, OtherArgs...>;
};
static_assert(
std::is_same<
fake_cont<int, fake_alloc<int>>,
typename sample_rebind<fake_cont<int>, double>::type
>::value,
"This should pass!"
);
Run Code Online (Sandbox Code Playgroud)
正如您所看到的那样,期望的行为是最终static_assert应该通过,但不幸的是,它甚至没有达到这一点,因为static_assert在尝试调用构造函数fake_cont时触发了in .std::is_constructible<>fake_cont
在真正的代码fake_cont是libc ++的std::vector,所以我不能修改它的胆量或std::is_constructible胆量.
对于解决这个特定问题的任何建议都表示赞赏,static_assert特别感谢SFINAE周围的任何建议.
编辑:is_same的第一部分应该是 fake_cont<int, fake_alloc<int>>
编辑2:如果您注释掉static_assert的fake_cont,它编译(铛3.5).这就是我想要的.所以我只需要一些方法来避免static_assert进入fake_cont.
namespace details {
template<class T,class=void>
struct extra_test_t: std::true_type {};
}
Run Code Online (Sandbox Code Playgroud)
然后我们将额外的测试折叠到:
template<class...>struct types{using type=types;};
template<template<typename...> class Container, typename T, typename U, typename... OtherArgs>
struct sample_rebind<
Container<T, OtherArgs...>,
U,
std::enable_if_t<
details::extra_test_t< types< Container<T, OtherArgs...>, U > >::value
&& std::is_constructible<
Container<T, OtherArgs...>,
Container<U, OtherArgs...>
>::value
>
> {
using type = Container<U, OtherArgs...>;
};
Run Code Online (Sandbox Code Playgroud)
我们编写额外的测试:
namespace details {
template<class T, class Alloc, class U>
struct extra_test_t<
types<std::vector<T,Alloc>, U>,
typename std::enable_if<
std::is_same<value_type, typename Alloc::value_type>::value
>::type
> : std::true_type {};
template<class T, class Alloc, class U>
struct extra_test_t<
types<std::vector<T,Alloc>, U>,
typename std::enable_if<
!std::is_same<value_type, typename Alloc::value_type>::value
>::type
> : std::false_type {};
}
Run Code Online (Sandbox Code Playgroud)
基本上,这让我们可以在测试中注入“补丁”以匹配static_assert.
如果我们有is_std_container<T>和get_allocator<T>,我们可以写:
namespace details {
template<template<class...>class Z,class T, class...Other, class U>
struct extra_test_t<
types<Z<T,Other...>>, U>,
typename std::enable_if<
is_std_container<Z<T,Other...>>>::value
&& std::is_same<
value_type,
typename get_allocator<Z<T,Other...>>::value_type
>::value
>::type
> : std::true_type {};
template<class T, class Alloc, class U>
struct extra_test_t<
types<std::vector<T,Alloc>, U>,
typename std::enable_if<
is_std_container<Z<T,Other...>>>::value
&& !std::is_same<
value_type,
typename get_allocator<Z<T,Other...>>::value_type
>::value
>::type
> : std::false_type {};
}
Run Code Online (Sandbox Code Playgroud)
或者我们可以直接说任何有allocator_type可能的东西都不能反弹。
解决此问题的一种更具容器意识的方法是提取分配器类型 ( ),并以某种方式::allocator_type重新绑定 to 来替换容器参数列表中分配器类型的所有实例。这仍然很棘手,因为有一个类型的分配器,并且无法以通用方式区分键和值。TUstd::map<int, int>std::allocator< std::pair<const int, int> >intint