c++ - 改进模板类中的编译时错误消息
问题描述
我有一个模板类,它应该接受某种对象的某种容器(std::array 和 std::vector)(在这个例子中是字符串和双精度数)。
如果类是从错误的对象组合构造的,我的目标是提供一些明确的编译错误。以下代码在 Visual Studio 17 版本 15.9.0 中编译。
///Performing checks
namespace checks
{
template <typename T>
struct CorrectType {
enum { value = false };
};
template <>
struct CorrectType<std::string> {
enum { value = true };
};
template <>
struct CorrectType<double> {
enum { value = true };
};
template <typename T>
struct CorrectContainer {
enum { value = false };
};
template <typename T, typename A>
struct CorrectContainer<std::vector<T, A>> {
enum { value = CorrectType<T>::value };
};
template <typename T, std::size_t N>
struct CorrectContainer<std::array<T, N>> {
enum { value = CorrectType<T>::value };
};
template <class Container>
void constexpr check(){
static_assert(checks::CorrectContainer<Container>::value, "Wrong container: only vectors/arrays of doubles/strings are accepted");
}
}
template <typename Container>
class Wrapper
{
public:
explicit Wrapper(const Container &container) : container_(container), size_(container.size())
{
//type checking is performed
checks::check<Container>();
}
void display() const {
for (int i = 0; i < size_; i++)
std::cout << this->container_[i] << " ";
std::cout << std::endl;
}
private:
Container container_;
int size_ = 0;
};
int main()
{
//Ok
Wrapper array_wrapper(std::array<double, 5>{0.0,1.0,2.0,3.0,4.0});
array_wrapper.display();
//Ok
Wrapper string_wrapper(std::array<std::string, 3>{ "a","b","c" });
string_wrapper.display();
//Error - working as intended but not clear what went wrong
Wrapper<std::vector<int>> vector_wrapper({ 1,2,3});
vector_wrapper.display();
}
上面的代码按预期工作,但错误是模棱两可的:我们无法理解容器是否错误或包含的对象类型。而且,如果模板化的对象没有size
成员函数,它会过早地失败。
解决方案
据我了解您的查询,无效类型检测可能可以概括为
template<class> struct ValidType;
template<template<class...> class> struct ValidContainer: std::false_type {};
template<> struct ValidContainer<std::vector>: std::true_type {};
template<class> struct ValidType: std::false_type {};
template<class> struct ValidType<double>: std::true_type {};
template<class> struct ValidType<std::string>: std::true_type {};
template<class> struct ValidArgument {
static_assert(false, "Both container and element type are wrong");
};
template<template<class...> class Ctr, class T, class... Ts>
struct ValidArgument<Ctr<T, Ts...>> {
static_assert(ValidContainer<Ctr>::value || ValidType<T>::value
, "Both container and element type are wrong");
static_assert(ValidContainer<Ctr>::value, "Container type is wrong");
static_assert(ValidType<T>::value, "Element type is wrong");
};
template<class T, std::size_t n> struct ValidArgument<std::array<T, n>> {
static_assert(ValidType<T>::value, "Element type is wrong");
};
(注意这不是真正的代码,只是一个想法的演示。)
在具有非类型参数的意义上,数组仍然是邪恶的,std::array
因此您不能有一个检查容器的单个模板,最终检查仍然是类型 0 类型,容器在一般情况下检查std::array
并被处理分别地。
或者,ValidType
可以稍微紧凑一些:
template<class T> using ValidType = std::bool_constant<
std::is_same_v<T, double> || std::is_same_v<T, std::string>>;
或者
template<class T> using ValidType = std::disjunction<
std::is_same<T, double>, std::is_same<T, std::string>>;
或者一个不太标准的类型匹配类。例如:
template<class T, class... Ts> inline constexpr bool is_one_of_v =
std::disjunction_v<std::is_same<T, Ts>...>;
template<class T> using ValidType =
std::bool_constant<is_one_of_v<T, double, std::string>>;
这样,您以后获得流氓专业化的可能性就较小。
推荐阅读
- c# - 使用相同的 AAD 令牌调用 SharePoint Online
- regex - 使用正则表达式验证密码
- pentaho - Pentaho/POI 抛出 InvocationTargetException
- javascript - Three.js OrbitControls如何在平移时逐渐平稳地停止,而不是立即停止?
- android - 在我的设备中运行 react-native 代码时出现问题
- arrays - 从大多数线性递增数组中删除异常值
- python - 如果来自文件 excel 或 csv 的数据,如何使用停用词 sastrawi 库 python
- ajax - 如何修复已被 api 阻止的 java 脚本中的 cors 策略
- r - 如何添加 element_text 色标作为图例?
- javascript - 如何解决这个(不是函数)错误?