如何使SFINAE发挥static

如何使SFINAE发挥static

本文介绍了如何使SFINAE发挥static_assert的作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新

我发布了中可能有一个 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的作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 05:36