在C ++ 11中有选择地禁用模板成员的简单方法

时间:2015-01-09 10:13:01

标签: c++ templates c++11

让我们从代码开始(请注意,缩短代码仅显示有问题的部分。)

#include <type_traits>
#include <utility>
#include <list>
#include <forward_list>
#include <functional>

template<typename Container, typename Compare>
class SortedContainer
{
public:

    template<typename... Args>
    auto erase(Args&&... args) -> decltype(std::declval<Container>().erase(std::forward<Args>(args)...))
    {
        return container_.erase(std::forward<Args>(args)...);
    }

    decltype(std::declval<const Container>().size()) size() const
    {
        return container_.size();
    }

private:

    /// container used for keeping elements
    Container container_;
};

SortedContainer<std::list<int>, std::less<int>> list;
SortedContainer<std::forward_list<int>, std::less<int>> forward_list;

int main()
{

}

如果基础SortedContainer没有匹配签名所需的功能,我希望有选择地禁用Container模板中的某些功能。

上面的示例失败,因为std::forward_list没有erase()size()函数:

$ g++ -std=c++11 test.cpp 
test.cpp: In instantiation of ‘class SortedContainer<std::forward_list<int>, std::less<int> >’:
test.cpp:30:57:   required from here
test.cpp:13:7: error: ‘class std::forward_list<int>’ has no member named ‘erase’
  auto erase(Args&&... args) -> decltype(std::declval<Container>().erase(std::forward<Args>(args)...))
       ^
test.cpp:18:51: error: ‘const class std::forward_list<int>’ has no member named ‘size’
  decltype(std::declval<const Container>().size()) size() const
                                                   ^

我无法将std::enable_ifstd::is_member_function_pointer一起使用,因为erase()已超载。也许一些聪明的演员会对此有所帮助吗?

我希望它能够#14;只是工作&#34;,因为这与这个答案https://stackoverflow.com/a/9531274/157344的最后一个解决方案非常相似,但它不会,即使我提供类型( typename Container::iterator()中的逗号之后的decltype - 错误消息是相同的。

我希望有一些不错的解决方案,不需要实现十几个has_*() constexpr函数来检查这个特定函数是否存在。我找不到任何关于&#34的例子;检查这个带有这个参数的成员是否存在&#34;灵活的模板,所以它可以像:

has_function<&Container::erase(std::forward<Args>(args)...)>::value
has_function<&Container::size()>::value

无需单独执行has_erase()has_size()

我还希望 NOT 专门针对SortedContainer的{​​{1}}课程,因为我并不关心实际类型是什么,只是或者它没有转发包装所需的功能。

1 个答案:

答案 0 :(得分:7)

不是直接使用Container,而是使用Container作为默认参数添加额外的模板参数,并使用:

template<typename... Args, typename C = Container>
//                       ^^^^^^^^^^^^^^^^^^^^^^^^
auto erase(Args&&... args) -> decltype(std::declval<C>().erase(std::forward<Args>(args)...))
//                                                  ^

同样为size()

template<typename C = Container>
decltype(std::declval<const C>().size()) size() const