如何使用索引运算符为容器定义类型特征?
How to define type trait for containers with index operator?
我有以下类型特征来区分基本类型和容器类型:
template <typename T>
using enable_if_fundamental_t = std::enable_if_t<std::is_fundamental_v<T>>;
template <typename T, typename = void>
struct is_container : std::false_type {};
template <typename T>
struct is_container<
T
, std::void_t<
typename T::value_type
, typename T::size_type
, typename T::allocator_type
, typename T::iterator
, typename T::const_iterator
, decltype(std::declval<T>().size())
, decltype(std::declval<T>().begin())
, decltype(std::declval<T>().end())
, decltype(std::declval<T>().cbegin())
, decltype(std::declval<T>().cend())
>
> : std::true_type {};
template <typename T>
constexpr bool is_container_v = is_container<T>::value;
template <typename T>
using enable_if_container_t = std::enable_if_t<is_container_v<T>>;
它们与以下函数一起使用:
template <typename T, typename = enable_if_fundamental_t<T>>
void foo(T)
{
std::cout << "This is a fundamental type" << std::endl;
}
template <typename C, typename = enable_if_container_t<C>>
void foo(const C& c)
{
std::cout << "This is a container type" << std::endl;
}
使用以下参数:
std::list<std::uint32_t> l;
std::vector<std::uint32_t> v;
std::map<std::string, std::uint32_t> m;
std::unordered_map<std::string, std::uint32_t> um;
std::uint32_t i = 42;
foo(l);
foo(v);
foo(m);
foo(um);
foo(i);
而且它们工作正常。
现在我想区分超载 operator[]
的容器和其他容器。我尝试了以下代码:
template <typename T, typename = void>
struct is_container_with_index_operator_with_size_type : std::false_type {};
template <typename T>
struct is_container_with_index_operator_with_size_type<
T
, std::void_t<
enable_if_container_t<T>
, decltype(std::declval<T>().operator[](std::declval<typename T::size_type>()))
>
> : std::true_type {};
template <typename T>
constexpr bool is_container_with_index_operator_with_size_type_v =
is_container_with_index_operator_with_size_type<T>::value;
template <typename T, typename = void>
struct is_container_with_index_operator_with_key_type : std::false_type {};
template <typename T>
struct is_container_with_index_operator_with_key_type<
T
, std::void_t<
enable_if_container_t<T>
, typename T::key_type
, decltype(std::declval<T>().operator[](std::declval<typename T::key_type>()))
>
> : std::true_type {};
template <typename T>
constexpr bool is_container_with_index_operator_with_key_type_v =
is_container_with_index_operator_with_key_type<T>::value;
template <typename T>
constexpr bool is_container_with_index_operator_v =
is_container_with_index_operator_with_size_type_v<T> ||
is_container_with_index_operator_with_key_type_v<T>;
template <typename T>
constexpr bool is_container_without_index_operator_v =
is_container_v<T> &&
!is_container_with_index_operator_v<T>;
template <class T>
using enable_if_container_with_index_operator_t =
std::enable_if_t<is_container_with_index_operator_v<T>>;
template <class T>
using enable_if_container_without_index_operator_t =
std::enable_if_t<is_container_without_index_operator_v<T>>;
具有以下重载:
template <typename T, typename = enable_if_fundamental_t<T>>
void foo(T)
{
std::cout << "This is a fundamental type" << std::endl;
}
template <typename C, typename = enable_if_container_without_index_operator_t<C>>
void foo(const C&)
{
std::cout << "This is a container type without index operator" << std::endl;
}
template <typename C, typename = enable_if_container_with_index_operator_t<C>>
void foo(const C&)
{
std::cout << "This is a container type with index operator" << std::endl;
}
使用与上面相同的参数,它给我带来了错误:
error C2995: 'void foo(const C &)': function template has already been defined
我尝试了上面代码的几种变体,但我没能以正确的方式完成它。
如何以正确的方式做到这一点,是否有可能实现更简单的代码?例如,对于 operator[]
?
使用 size_type
和 key_type
的容器,没有单独的元函数
我正在使用 Visual Studio 2017 版本 15.7.2 和 v141 工具集并启用 /std:c++17
.
那是因为您不能仅根据默认模板参数值来重载函数。您可以通过以下方式重现:
template <typename T, typename = std::enable_if_t<(sizeof(T) > 2)>> void foo() {}
template <typename T, typename = std::enable_if_t<!(sizeof(T) > 2)>> void foo() {}
// error: redefinition of 'template<class T, class> void foo()'
一个可能的解决方案是在模板参数的类型中使用enable_if_t
:
template <typename T, std::enable_if_t<(sizeof(T) > 2), int> = 0> void foo() {}
template <typename T, std::enable_if_t<!(sizeof(T) > 2), int> = 0> void foo() {}
或在 return 中输入:
template <typename T> std::enable_if_t<(sizeof(T) > 2)/*,void*/> foo() {}
template <typename T> std::enable_if_t<!(sizeof(T) > 2)/*,void*/> foo() {}
我有以下类型特征来区分基本类型和容器类型:
template <typename T>
using enable_if_fundamental_t = std::enable_if_t<std::is_fundamental_v<T>>;
template <typename T, typename = void>
struct is_container : std::false_type {};
template <typename T>
struct is_container<
T
, std::void_t<
typename T::value_type
, typename T::size_type
, typename T::allocator_type
, typename T::iterator
, typename T::const_iterator
, decltype(std::declval<T>().size())
, decltype(std::declval<T>().begin())
, decltype(std::declval<T>().end())
, decltype(std::declval<T>().cbegin())
, decltype(std::declval<T>().cend())
>
> : std::true_type {};
template <typename T>
constexpr bool is_container_v = is_container<T>::value;
template <typename T>
using enable_if_container_t = std::enable_if_t<is_container_v<T>>;
它们与以下函数一起使用:
template <typename T, typename = enable_if_fundamental_t<T>>
void foo(T)
{
std::cout << "This is a fundamental type" << std::endl;
}
template <typename C, typename = enable_if_container_t<C>>
void foo(const C& c)
{
std::cout << "This is a container type" << std::endl;
}
使用以下参数:
std::list<std::uint32_t> l;
std::vector<std::uint32_t> v;
std::map<std::string, std::uint32_t> m;
std::unordered_map<std::string, std::uint32_t> um;
std::uint32_t i = 42;
foo(l);
foo(v);
foo(m);
foo(um);
foo(i);
而且它们工作正常。
现在我想区分超载 operator[]
的容器和其他容器。我尝试了以下代码:
template <typename T, typename = void>
struct is_container_with_index_operator_with_size_type : std::false_type {};
template <typename T>
struct is_container_with_index_operator_with_size_type<
T
, std::void_t<
enable_if_container_t<T>
, decltype(std::declval<T>().operator[](std::declval<typename T::size_type>()))
>
> : std::true_type {};
template <typename T>
constexpr bool is_container_with_index_operator_with_size_type_v =
is_container_with_index_operator_with_size_type<T>::value;
template <typename T, typename = void>
struct is_container_with_index_operator_with_key_type : std::false_type {};
template <typename T>
struct is_container_with_index_operator_with_key_type<
T
, std::void_t<
enable_if_container_t<T>
, typename T::key_type
, decltype(std::declval<T>().operator[](std::declval<typename T::key_type>()))
>
> : std::true_type {};
template <typename T>
constexpr bool is_container_with_index_operator_with_key_type_v =
is_container_with_index_operator_with_key_type<T>::value;
template <typename T>
constexpr bool is_container_with_index_operator_v =
is_container_with_index_operator_with_size_type_v<T> ||
is_container_with_index_operator_with_key_type_v<T>;
template <typename T>
constexpr bool is_container_without_index_operator_v =
is_container_v<T> &&
!is_container_with_index_operator_v<T>;
template <class T>
using enable_if_container_with_index_operator_t =
std::enable_if_t<is_container_with_index_operator_v<T>>;
template <class T>
using enable_if_container_without_index_operator_t =
std::enable_if_t<is_container_without_index_operator_v<T>>;
具有以下重载:
template <typename T, typename = enable_if_fundamental_t<T>>
void foo(T)
{
std::cout << "This is a fundamental type" << std::endl;
}
template <typename C, typename = enable_if_container_without_index_operator_t<C>>
void foo(const C&)
{
std::cout << "This is a container type without index operator" << std::endl;
}
template <typename C, typename = enable_if_container_with_index_operator_t<C>>
void foo(const C&)
{
std::cout << "This is a container type with index operator" << std::endl;
}
使用与上面相同的参数,它给我带来了错误:
error C2995: 'void foo(const C &)': function template has already been defined
我尝试了上面代码的几种变体,但我没能以正确的方式完成它。
如何以正确的方式做到这一点,是否有可能实现更简单的代码?例如,对于 operator[]
?
size_type
和 key_type
的容器,没有单独的元函数
我正在使用 Visual Studio 2017 版本 15.7.2 和 v141 工具集并启用 /std:c++17
.
那是因为您不能仅根据默认模板参数值来重载函数。您可以通过以下方式重现:
template <typename T, typename = std::enable_if_t<(sizeof(T) > 2)>> void foo() {}
template <typename T, typename = std::enable_if_t<!(sizeof(T) > 2)>> void foo() {}
// error: redefinition of 'template<class T, class> void foo()'
一个可能的解决方案是在模板参数的类型中使用enable_if_t
:
template <typename T, std::enable_if_t<(sizeof(T) > 2), int> = 0> void foo() {}
template <typename T, std::enable_if_t<!(sizeof(T) > 2), int> = 0> void foo() {}
或在 return 中输入:
template <typename T> std::enable_if_t<(sizeof(T) > 2)/*,void*/> foo() {}
template <typename T> std::enable_if_t<!(sizeof(T) > 2)/*,void*/> foo() {}