3

我创建了一个container_traits类来检查容器是否std::array存在。但它无法捕获从std::array. 有什么解决办法吗?

#include <vector>
#include <array>
#include <iostream>

using namespace std;

template<typename C>
struct container_traits { constexpr static bool is_array = false; };
template<typename T, size_t S>
struct container_traits<std::array<T,S>> { constexpr static bool is_array = true; };

template<typename T, size_t S>
struct A : public std::array<T,S> {};

int main()
{
    cout << container_traits<A<int, 5>>::is_array << endl;              // must return 1
    cout << container_traits<std::array<int, 10>>::is_array << endl;    // must return 1
    cout << container_traits<std::vector<int>>::is_array << endl;       // must return 0
    return 0;
}
4

2 回答 2

7

你可以使用std::is_base_of

template <typename C>
struct container_traits {
  constexpr static bool is_array = false;
};

template <template <typename, std::size_t> class C,
          typename T, std::size_t N>
struct container_traits<C<T,N>> {
  constexpr static bool is_array = std::is_base_of<std::array<T,N>, C<T,N>>::value;
};

看到它在行动

它基本上专门用于任何带有两个参数的模板类型。在该专业化中, 的值由is_array决定std::is_base_of

于 2013-03-25T14:05:48.467 回答
6

作者注:请不要为这个解决方案投票。投票给 sftrabbit,因为它比我的好。不过我不会删除,因为虽然有缺陷,但有些人觉得这个想法很有趣。

这给出了您想要的结果:

template<typename C>
struct container_traits {

private:

   template <typename T, size_t N>
   static char (&is_array_helper(const std::array<T, N>&))[1];

   static char (&is_array_helper(...))[2];

public:

    constexpr static bool is_array =
        sizeof(is_array_helper(std::declval<C>())) == sizeof(char[1]);

};

注意

值得一提的是,对于从std::array<T, N>(例如A)派生的类,继承必须是public,否则代码无法编译。要解决此问题,您可以使用std::is_base_of或应用一些 SFINAE 技术。然而,关于可访问性的 SFINAE 规则已从 C++03 更改为 C++11,当我前段时间测试时,一些主要编译器没有实现新规则。可能是他们现在做的。

我建议问题的作者等着看是否有更好的解决方案出现(我希望这会发生)。

于 2013-03-25T14:11:10.877 回答