#include <iostream>
#include <vector>
#include <list>
#include <type_traits>
template <typename T>
class MyContainer {
private:
T data;
public:
MyContainer(const T& value) : data(value) {}
// 辅助模板,判断类型是否为可迭代容器
template <typename U>
static auto has_begin_end(U&& u) -> decltype(std::declval<U>().begin(), std::declval<U>().end(), std::true_type());
template <typename U>
static std::false_type has_begin_end(...);
// SFINAE 辅助模板
template <typename U, typename = void>
struct is_iterable_container : std::false_type {};
template <typename U>
struct is_iterable_container<U, decltype(has_begin_end(std::declval<U>()))> : std::true_type {};
// 针对可迭代容器的 processData 实现
template <typename U = T, typename = std::enable_if_t<is_iterable_container<U>::value>>
void processData() {
for (auto& element : data) {
element = element * element;
}
}
// 针对基本算术类型的 processData 实现
template <typename U = T, typename = std::enable_if_t<std::is_arithmetic<U>::value &&!is_iterable_container<U>::value>>
void processData() {
data = data * data;
}
};
int main() {
MyContainer<std::vector<int>> vecContainer({1, 2, 3});
vecContainer.processData();
for (int num : vecContainer) {
std::cout << num << " ";
}
std::cout << std::endl;
MyContainer<int> intContainer(5);
intContainer.processData();
std::cout << intContainer << std::endl;
// 以下代码会在编译期报错,因为 MyContainer<std::string> 没有有效的 processData 函数
// MyContainer<std::string> strContainer("test");
// strContainer.processData();
return 0;
}
- 判断可迭代容器:
- 使用
has_begin_end
模板函数,通过 decltype
检查类型是否有 begin
和 end
成员函数,以此判断是否为可迭代容器。
is_iterable_container
模板类利用 has_begin_end
辅助判断类型是否为可迭代容器。
processData
成员函数重载:
- 第一个
processData
模板函数通过 std::enable_if_t<is_iterable_container<U>::value>
来判断存储类型是否为可迭代容器,如果是,则遍历容器并对每个元素求平方。
- 第二个
processData
模板函数通过 std::enable_if_t<std::is_arithmetic<U>::value &&!is_iterable_container<U>::value>
来判断存储类型是否为基本算术类型且不是可迭代容器,如果是,则直接对数据求平方。
main
函数:
- 测试了
MyContainer
存储 std::vector<int>
和 int
类型时 processData
函数的正确性。同时注释掉了存储 std::string
类型时的调用,因为 std::string
类型没有有效的 processData
函数,会在编译期报错。