我正在尝试创建通用容器包装器。
template<typename type>
class ContainerWrapper
{
public:
using allocator_type = typename type::allocator_type;
using size_type = typename type::size_type;
using difference_type = typename type::difference_type;
using pointer = typename type::pointer;
using const_pointer = typename type::const_pointer;
using reference = typename type::reference;
using const_reference = typename type::const_reference;
using iterator = typename type::iterator;
using const_iterator = typename type::const_iterator;
using reverse_iterator = typename type::reverse_iterator;
using const_reverse_iterator = typename type::const_reverse_iterator;
using value_type = typename type::value_type;
iterator begin() noexcept { return container.begin(); }
const_iterator begin() const noexcept { return container.begin(); }
iterator end() noexcept { return container.end(); }
const_iterator end() const noexcept { return container.end(); }
reverse_iterator rbegin() noexcept { return container.rbegin(); }
const_reverse_iterator rbegin() const noexcept { return container.rbegin(); }
reverse_iterator rend() noexcept { return container.rend(); }
const_reverse_iterator rend() const noexcept { return container.rend(); }
const_iterator cbegin() const noexcept { return container.cbegin(); }
const_iterator cend() const noexcept { return container.cend(); }
const_reverse_iterator crbegin() const noexcept { return container.crbegin(); }
const_reverse_iterator crend() const noexcept { return container.crend(); }
protected:
ContainerWrapper() {}
type& getContainer() { return container; }
const type& getContainer() const { return container; }
private:
type container;
};
但并非所有容器都有各种迭代器。是否可以仅在容器类型存在时公开它们?像
这样的东西using const_reverse_iterator = typename std::enable_if_t<std::is_class<typename type::const_reverse_iterator>::value, typename type::const_reverse_iterator>::type;
我只能使用C ++ 11(gcc 4.7)。当然,我可以为不同的容器创建不同的包装器,但我更喜欢使用一个通用包装器。
答案 0 :(得分:3)
您可以为每种类型创建一个基类,并使用SFINAE专门化该基础:
template <typename...> struct void_type
{
using type = void;
};
template <typename T, typename = void> struct ContainerWrapper_Base_const_reverse_iterator{};
template <typename T> struct ContainerWrapper_Base_const_reverse_iterator
<T, typename void_type<typename T::const_reverse_iterator>::type>
{
using const_reverse_iterator = typename T::const_reverse_iterator;
};
// ... Similar bases for each conditional alias.
template <typename type> class ContainerWrapper
: public ContainerWrapper_Base_const_reverse_iterator<type>
// ... Inherit from all those bases
{
// ...
};
如果您确定它们总是一起定义或根本没有定义,您可以将类似的类型放入单个基础中。
此外,您可能希望使用预处理器生成这些基础,可能还有x-macros。
另请注意,上述代码可以使用C ++ 17 std::void_t
或手写template <typename...> using void_t = void;
进行简化,但在GCC 4.7中无法正常工作。
答案 1 :(得分:3)
原始阵列容器是否足够你? 无论如何:
使用SFINAE,重载分辨率和继承。
namespace detail {
using std::rbegin;
template <class T>
auto reverse_iter_typedefs(long) {
struct {} r;
return r;
}
template <class T, class X = decltype(rbegin(std::declval<T&>()))>
auto reverse_iter_typedefs(int) {
struct {
using reverse_iterator = decltype(rbegin(std::declval<T&>()));
} r;
return r;
}
}
template <class T>
ContainerWrapper : decltype(detail::reverse_iter_typedefs<T>(1)), ...
答案 2 :(得分:1)
您有没有理由不使用auto
功能?
使用HolyBlackCat的代码,您应该考虑将明确(或应该)组合在一起的类型和函数分组,并使用auto来避免模糊函数调用:
template <typename...> struct void_type { using type = void; };
template<typename type, typename = void>
struct conditional_derive_iterator {
protected:
conditional_derive_iterator(type*const container) {}
};
template<typename type>
struct conditional_derive_iterator
<type, typename void_type<typename type::iterator>::type>
{
// grouping types
using iterator = typename type::iterator;
using const_iterator = typename type::const_iterator;
// this should work with gcc. avoids ambiguity. cleaner code
inline constexpr auto begin() const noexcept { return c->begin(); }
inline constexpr auto end() const noexcept { return c->end(); }
protected:
// this will let you get access to the container
conditional_derive_iterator(type*const container) : c(container) {}
private:
type*const c;
};
template<typename type>
class ContainerWrapper :
public conditional_derive_iterator<type>
{
public:
// for demo purpose. however, make sure to pass &container to your bases
ContainerWrapper(const type& c) :
container(c),
conditional_derive_iterator(&container) {}
// continue code...
};
class UselessType{};
void main()
{
ContainerWrapper<UselessType> a(UselessType{});
ContainerWrapper<std::vector<int>> b({1,2,3});
auto itera = a.begin(); // this will not compile
auto iterb = b.begin(); // this will compile
}
虽然auto func()...
是c ++ 14及以上,但我相信auto func() -> return_type
是c ++ 11,所以begin / end看起来像这样:
inline constexpr auto begin() const noexcept -> decltype(iterator{}, const_iterator{}) { return c->begin(); }
以下是一个示例:https://repl.it/K9g5/0
您还应该查看此会员检测器:https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Member_Detector
它可以派上用场。