如何在声明时静态检查模板化的 class?
How do I statically check my templated class at declaration time?
在 C# 或 Java 中,以下代码无法编译,因为我 "forgot" class 声明中的 where
部分指定 T 是某物的实例定义 add
方法。
class C<T> {
T make(T t) {
return t.add(t);
}
}
如果我为模板参数指定不完整 requires
,我希望在 C++ 中获得类似的编译时检查。
template <typename T>
requires true
class C {
public:
T make() {
return T{};
}
};
我想得到上面 C++ 代码的编译错误,说明方法 c.make
依赖于 T
是可默认构造的,但是 [=15] 中没有捕获到=] 对 T
.
的约束
我能否让编译器检查我的 requires
约束集是否足以涵盖 class 实现所做的一切?
我为此使用 gcc (GCC) 10.0.0 20191207(实验版)。
template <class T>
requires std::is_default_constructible_v<T>
class C
{
static_assert(std::is_default_constructible_v<T>,
"T is not default-constructible");
};
struct valid
{
};
class invalid
{
invalid() = delete;
};
int main()
{
C<valid>();
// C<invalid>(); // assertion fails.
}
您可以在 class 定义内的任何位置写入 static_assert
,与 requires
一起。这会给你一个你想要的错误信息。
UPDATE 阅读了您提供的 link 后,我想您只需要多次检查即可。
你可以写一个特征结构:
// SFINAE to check if has "add"
template <class T, class = std::void_t<>>
struct has_method_add
{
constexpr static bool value = false;
};
template <class T>
struct has_method_add<T, std::void_t<decltype(&T::add)>>
{
constexpr static bool value = true;
};
template <class T, class = std::void_t<>>
struct has_operator_remainder
{
constexpr static bool value = false;
};
template <class T>
struct has_operator_remainder<T, std::void_t<decltype(&T::operator%=)>>
{
constexpr static bool value = true;
};
template <class T>
struct error_missing_add
{
constexpr static bool value = has_method_add<T>::value;
static_assert(has_method_add<T>::value, "T::add is not defined");
};
template <class T>
struct error_missing_remainder
{
constexpr static bool value = has_operator_remainder<T>::value;
static_assert(has_operator_remainder<T>::value, "T::operator%= is not defined");
};
template <class T>
class C
{
static_assert(std::conjunction_v<error_missing_add<T>, error_missing_remainder<T>>);
// impl...
};
struct valid
{
void add();
int operator%=(int) const;
};
struct missing_add
{
int operator%=(int) const;
};
struct missing_remainder
{
void add();
};
int main()
{
C<valid>{};
C<missing_add>{}; // error: T::add is not defined
C<missing_remainder>{}; // error: T::operator%= is not defined
return 0;
}
我要的是定义检查,目前显然是不可能的
C++2a concepts (formerly known as “Concepts Lite” and/or the Concepts TS) famously do not support “definition checking.” The idea of definition checking is that the programmer might write [...]
https://quuxplusone.github.io/blog/2019/07/22/definition-checking-with-if-constexpr/
8.2 Definition checking
Concepts currently do not prevent a template from using operations that are not specified in the requirements. Consider:
template<Number N>
void algo(vector<N>& v){
for (auto& x : v) x%=2;
}
Our Number concept does not require %=, so whether a call of algo succeeds will depend not just on what is checked by the concept, but on the actual properties of the argument type: does the argument type have %=? If not, we get a late (instantiation time) error.
Some consider this a serious error. I don’t [...]
http://www.w.stroustrup.com/good_concepts.pdf
The current proposal checks interfaces and that's where the main benefits for users are, but not template definitions. That has been explicit from the start.
https://isocpp.org/blog/2016/02/a-bit-of-background-for-concepts-and-cpp17-bjarne-stroustrup
在 C# 或 Java 中,以下代码无法编译,因为我 "forgot" class 声明中的 where
部分指定 T 是某物的实例定义 add
方法。
class C<T> {
T make(T t) {
return t.add(t);
}
}
如果我为模板参数指定不完整 requires
,我希望在 C++ 中获得类似的编译时检查。
template <typename T>
requires true
class C {
public:
T make() {
return T{};
}
};
我想得到上面 C++ 代码的编译错误,说明方法 c.make
依赖于 T
是可默认构造的,但是 [=15] 中没有捕获到=] 对 T
.
我能否让编译器检查我的 requires
约束集是否足以涵盖 class 实现所做的一切?
我为此使用 gcc (GCC) 10.0.0 20191207(实验版)。
template <class T>
requires std::is_default_constructible_v<T>
class C
{
static_assert(std::is_default_constructible_v<T>,
"T is not default-constructible");
};
struct valid
{
};
class invalid
{
invalid() = delete;
};
int main()
{
C<valid>();
// C<invalid>(); // assertion fails.
}
您可以在 class 定义内的任何位置写入 static_assert
,与 requires
一起。这会给你一个你想要的错误信息。
UPDATE 阅读了您提供的 link 后,我想您只需要多次检查即可。
你可以写一个特征结构:
// SFINAE to check if has "add"
template <class T, class = std::void_t<>>
struct has_method_add
{
constexpr static bool value = false;
};
template <class T>
struct has_method_add<T, std::void_t<decltype(&T::add)>>
{
constexpr static bool value = true;
};
template <class T, class = std::void_t<>>
struct has_operator_remainder
{
constexpr static bool value = false;
};
template <class T>
struct has_operator_remainder<T, std::void_t<decltype(&T::operator%=)>>
{
constexpr static bool value = true;
};
template <class T>
struct error_missing_add
{
constexpr static bool value = has_method_add<T>::value;
static_assert(has_method_add<T>::value, "T::add is not defined");
};
template <class T>
struct error_missing_remainder
{
constexpr static bool value = has_operator_remainder<T>::value;
static_assert(has_operator_remainder<T>::value, "T::operator%= is not defined");
};
template <class T>
class C
{
static_assert(std::conjunction_v<error_missing_add<T>, error_missing_remainder<T>>);
// impl...
};
struct valid
{
void add();
int operator%=(int) const;
};
struct missing_add
{
int operator%=(int) const;
};
struct missing_remainder
{
void add();
};
int main()
{
C<valid>{};
C<missing_add>{}; // error: T::add is not defined
C<missing_remainder>{}; // error: T::operator%= is not defined
return 0;
}
我要的是定义检查,目前显然是不可能的
C++2a concepts (formerly known as “Concepts Lite” and/or the Concepts TS) famously do not support “definition checking.” The idea of definition checking is that the programmer might write [...]
https://quuxplusone.github.io/blog/2019/07/22/definition-checking-with-if-constexpr/
8.2 Definition checking
Concepts currently do not prevent a template from using operations that are not specified in the requirements. Consider:
template<Number N>
void algo(vector<N>& v){
for (auto& x : v) x%=2;
}
Our Number concept does not require %=, so whether a call of algo succeeds will depend not just on what is checked by the concept, but on the actual properties of the argument type: does the argument type have %=? If not, we get a late (instantiation time) error.
Some consider this a serious error. I don’t [...]
http://www.w.stroustrup.com/good_concepts.pdf
The current proposal checks interfaces and that's where the main benefits for users are, but not template definitions. That has been explicit from the start.
https://isocpp.org/blog/2016/02/a-bit-of-background-for-concepts-and-cpp17-bjarne-stroustrup