如何使用概念约束仿函数的参数?
How do I constrain the parameter(s) of a functor using concepts?
我有以下概念:
template <typename T>
concept FunctorInt = requires(T a, int b) {
a.operator()(b); //require the () operator with a single int parameter.
};
我在以下函数中使用它:
template <FunctorInt functor_t>
void for_each_sat_lit(const int ClauseIndex, functor_t functor) {
auto LitIndex = -1;
uint32_t Count = h_SatisfiedLitCount[ClauseIndex];
if constexpr (!satlit) { Count = h_LiteralsInClauseCount[ClauseIndex] - Count; }
for (uint32_t dummy = 0; dummy < Count; dummy++) {
LitIndex = NextSetBit(h_SATLiteralBits[ClauseIndex], LitIndex);
functor(LitIndex); //LitIndex must be an int.
}
}
编译通过。但是,当我尝试通过将概念更改为
来破坏代码时
template <typename T>
concept FunctorInt = requires(T a, float b) {
a.operator()(b); //I intend to require the () operator with a single float parameter.
};
它仍然可以编译,这意味着它根本没有约束仿函数。
如何限制仿函数使其只能有一个 int 参数?
MSVC:concepts.cpp
#include <concepts>
template <typename T>
concept FunctorInt = requires(T a, int b) {
a.operator()(b); //require the () operator with a single int parameter.
};
template <typename T>
concept FunctorFloat = requires(T a, float b) {
a.operator()(b); //require the () operator with a single float parameter.
};
void Loop(FunctorInt auto functor) {
for (auto i = 0; i < 10; i++) {
functor(i);
}
}
void LoopShouldNotCompile(FunctorFloat auto functor) {
for (auto i = 0; i < 10; i++) {
functor(i); //<< i is not a float.
}
}
int main(const int argc, const char* argv[]) {
Loop( [](int a){ printf("%i", a); });
LoopShouldNotCompile([](float a){ printf("%f", a); });
}
如果我使用 std::invocable
更改 FunctorInt
和 FunctorFloat
的定义,同样的问题仍然存在:
concept FunctorInt = std::invocable<int>;
concept FunctorFloat = std::invocable<float>;
一切仍然编译,而它应该在 LoopShouldNotCompile
.
上给出编译错误
更新:
我决定:
template <typename T>
concept FunctorInt =
requires() { [](void(T::*)(int) const){}(&T::operator()); }
|| requires() { [](void(T::*)(int) ){}(&T::operator()); };
它创建了一个只允许单个 int
参数并且不关心常量正确性的仿函数。
如果您想阻止函数接受您想要的任何其他类型,您可以使用类型匹配函数模板...例如
#include <concepts>
template <typename T>
requires std::same_as<T,float>
void func([[maybe_unused]]T f) {}
int main() {
//func(1); // doesn't compile
func(1.0f); // works
//func(1.0); // NB: fails again, because float!=double
}
编辑:更短
void func([[maybe_unused]]std::same_as<float> auto f) {}
你的概念检查是否可以用 int
调用类型
但你无法控制之前发生的 promotion/conversion。
您可以检查 T::operator()
的签名,但是之前的有效情况(如重载、模板函数、没有确切的函数但相似(const
、volatile
、...) ) 可能不再有效。
例如:
template <typename T>
concept FunctorInt = requires() {
[](void(T::*)(int) const){}(&T::operator());
};
void Loop(FunctorInt auto functor) { /**/ }
int main() {
Loop([](int a){ printf("%i", a); });
Loop([](float a){ printf("%f", a); }); // Not compile
}
我有以下概念:
template <typename T>
concept FunctorInt = requires(T a, int b) {
a.operator()(b); //require the () operator with a single int parameter.
};
我在以下函数中使用它:
template <FunctorInt functor_t>
void for_each_sat_lit(const int ClauseIndex, functor_t functor) {
auto LitIndex = -1;
uint32_t Count = h_SatisfiedLitCount[ClauseIndex];
if constexpr (!satlit) { Count = h_LiteralsInClauseCount[ClauseIndex] - Count; }
for (uint32_t dummy = 0; dummy < Count; dummy++) {
LitIndex = NextSetBit(h_SATLiteralBits[ClauseIndex], LitIndex);
functor(LitIndex); //LitIndex must be an int.
}
}
编译通过。但是,当我尝试通过将概念更改为
来破坏代码时template <typename T>
concept FunctorInt = requires(T a, float b) {
a.operator()(b); //I intend to require the () operator with a single float parameter.
};
它仍然可以编译,这意味着它根本没有约束仿函数。
如何限制仿函数使其只能有一个 int 参数?
MSVC:concepts.cpp
#include <concepts>
template <typename T>
concept FunctorInt = requires(T a, int b) {
a.operator()(b); //require the () operator with a single int parameter.
};
template <typename T>
concept FunctorFloat = requires(T a, float b) {
a.operator()(b); //require the () operator with a single float parameter.
};
void Loop(FunctorInt auto functor) {
for (auto i = 0; i < 10; i++) {
functor(i);
}
}
void LoopShouldNotCompile(FunctorFloat auto functor) {
for (auto i = 0; i < 10; i++) {
functor(i); //<< i is not a float.
}
}
int main(const int argc, const char* argv[]) {
Loop( [](int a){ printf("%i", a); });
LoopShouldNotCompile([](float a){ printf("%f", a); });
}
如果我使用 std::invocable
更改 FunctorInt
和 FunctorFloat
的定义,同样的问题仍然存在:
concept FunctorInt = std::invocable<int>;
concept FunctorFloat = std::invocable<float>;
一切仍然编译,而它应该在 LoopShouldNotCompile
.
更新:
我决定:
template <typename T>
concept FunctorInt =
requires() { [](void(T::*)(int) const){}(&T::operator()); }
|| requires() { [](void(T::*)(int) ){}(&T::operator()); };
它创建了一个只允许单个 int
参数并且不关心常量正确性的仿函数。
如果您想阻止函数接受您想要的任何其他类型,您可以使用类型匹配函数模板...例如
#include <concepts>
template <typename T>
requires std::same_as<T,float>
void func([[maybe_unused]]T f) {}
int main() {
//func(1); // doesn't compile
func(1.0f); // works
//func(1.0); // NB: fails again, because float!=double
}
编辑:更短
void func([[maybe_unused]]std::same_as<float> auto f) {}
你的概念检查是否可以用 int
调用类型
但你无法控制之前发生的 promotion/conversion。
您可以检查 T::operator()
的签名,但是之前的有效情况(如重载、模板函数、没有确切的函数但相似(const
、volatile
、...) ) 可能不再有效。
例如:
template <typename T>
concept FunctorInt = requires() {
[](void(T::*)(int) const){}(&T::operator());
};
void Loop(FunctorInt auto functor) { /**/ }
int main() {
Loop([](int a){ printf("%i", a); });
Loop([](float a){ printf("%f", a); }); // Not compile
}