如何使SFINAE发挥static_assert的作用 [英] How to make static_assert play nice with SFINAE
问题描述
更新
我发布了 rebind
的工作初稿作为答案这个问题。尽管我没有太多运气找到一种通用的方法来防止 static_assert
s破坏元功能。
I posted a working rough draft of rebind
as an answer to the question. Though I didn't have much luck finding a generic way to keep static_assert
s from breaking metafunctions.
基本上我想检查模板化类型 T< U,Args ...>
是否可以从其他类型 T< V,Args ...>
。其中 T
和 Args ...
在两种类型中都相同。问题是, T 中可能有一个
static_assert
,这完全破坏了我的元功能。
Basically I want to check if a templated type T<U, Args...>
can be constructed from some other type T<V, Args...>
. Where T
and Args...
is the same in both types. The problem is, T<>
might have a static_assert
in it that totally breaks my metafunction.
下面是我要做的事情的简要摘要。
Below is a rough summary of what I'm trying to do.
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!"
);
您可以看到所需的行为是最终的 static_assert
应该会通过,但是不幸的是,它甚至还没有达到那个程度,因为 fake_cont
中的 static_assert
当 std :: is_constructible<>
尝试调用 fake_cont
的构造函数时触发。
As you can see the desired behavior is that the final static_assert
should pass, but unfortunately, it doesn't even get to that point as the static_assert
in fake_cont
is triggered when std::is_constructible<>
attempts to call fake_cont
's constructor.
在真实代码 fake_cont
中是libc ++的 std :: vector
,所以我可以't修改它的胆量,或 std :: is_constructible
的胆量。
In the real code fake_cont
is libc++'s std::vector
, so I can't modify it's guts, or std::is_constructible
's guts.
任何解决此特定问题的建议对此问题表示赞赏,特别建议您对SFINAE的一般建议在 static_assert
左右。
Any advice for working around this specific issue is appreciated, and any advice in general for SFINAE'ing around static_assert
's is especially appreciated.
编辑:is_same的第一部分应该是 fake_cont< int,fake_alloc< int>>
the first part of the is_same should have been fake_cont<int, fake_alloc<int>>
编辑2 :如果您注释掉 fake_cont
中的 static_assert
,它将编译(clang 3.5)。这就是我想要的。所以我只需要一些方法来避免 fake_cont
中的 static_assert
。
Edit 2: If you comment out the static_assert
in fake_cont
, it compiles (clang 3.5). And that's what I want. So I just need some way to avoid the static_assert
in fake_cont
.
推荐答案
namespace details {
template<class T,class=void>
struct extra_test_t: std::true_type {};
}
然后我们对以下项进行额外的测试:
We then fold an extra test in:
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...>;
};
,然后编写额外的测试:
and we write the extra test:
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 {};
}
基本上,这使我们可以在测试中注入补丁以匹配 static_assert
。
basically, this lets us inject "patches" on our test to match the static_assert
.
如果我们有 is_std_container< T>
和 get_allocator< T>
,我们可以这样写:
If we had is_std_container<T>
and get_allocator<T>
, we could write:
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 {};
}
或者我们可以声明带有 allocator_type的任何内容
可能无法反弹。
or we could just state that anything with an allocator_type
probably cannot be rebound.
对这个问题更了解容器的方法是提取分配器类型( ::: allocator_type
),并将容器参数列表中所有分配器类型的实例替换为 T
与的重新绑定U
。这仍然很棘手,因为 std :: map< int,int>
具有类型为 std :: allocator<的分配器。 std :: pair< const int,int> >
,并且不能区分键 int
和值 int
A more container-aware approach to this problem would be to extract the allocator type (::allocator_type
), and replace all instances of the allocator type in the container argument list with a rebind of T
to U
somehow. This is still tricky, as std::map<int, int>
has an allocator of type std::allocator< std::pair<const int, int> >
, and distinguishing between the key int
and the value int
isn't possible in a generic way.
这篇关于如何使SFINAE发挥static_assert的作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!