在 C++11 中有选择地禁用模板成员的简单方法
Simple way to selectively disable template member in 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_if
与 std::is_member_function_pointer
一起使用,因为 erase()
已过载。也许一些聪明的演员会有所帮助?
我希望它会 "just work",因为这与此答案 中的最后一个解决方案非常相似,但它没有,即使我给出类型 (typename Container::iterator()
) 在 decltype
中的逗号之后 - 错误消息是相同的。
我希望有一些不错的解决方案,不需要实现一打 has_*()
constexpr 函数来检查这个特定函数是否存在。我找不到任何灵活的 "check whether this member with this arguments exists" 模板示例,因此它可以像这样工作:
has_function<&Container::erase(std::forward<Args>(args)...)>::value
has_function<&Container::size()>::value
无需单独实施 has_erase()
和 has_size()
。
我也更喜欢 NOT 将 SortedContainer
class 专门化为 std::forward_list
,因为我不在乎实际情况type 是,只是它是否具有转发包装器所需的功能。
不是直接使用 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
让我们从一段代码开始(请注意,它被缩短以仅显示有问题的部分)。
#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_if
与 std::is_member_function_pointer
一起使用,因为 erase()
已过载。也许一些聪明的演员会有所帮助?
我希望它会 "just work",因为这与此答案 中的最后一个解决方案非常相似,但它没有,即使我给出类型 (typename Container::iterator()
) 在 decltype
中的逗号之后 - 错误消息是相同的。
我希望有一些不错的解决方案,不需要实现一打 has_*()
constexpr 函数来检查这个特定函数是否存在。我找不到任何灵活的 "check whether this member with this arguments exists" 模板示例,因此它可以像这样工作:
has_function<&Container::erase(std::forward<Args>(args)...)>::value
has_function<&Container::size()>::value
无需单独实施 has_erase()
和 has_size()
。
我也更喜欢 NOT 将 SortedContainer
class 专门化为 std::forward_list
,因为我不在乎实际情况type 是,只是它是否具有转发包装器所需的功能。
不是直接使用 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