用概念重载函数
Overloading functions with concepts
(我正在学习概念和模板,所以如果我有什么非常错误的地方,请纠正我。)我有一个将概念作为参数的函数。我现在正试图重载这个采用更具体概念的函数。那会做“更具体的事情”或调用不太具体的功能。
template<typename T>
concept Concept1 = ...;
template<typename T>
concept MoreSpecificConcept = ...;
Concept1 <T> &&
...;
//...
void someFunc(const Concept1 auto& x)
{
//do general stuff
}
void someFunc(const MoreSpecificConcept auto& x)
{
if(...)
{
//do specific stuff
}
else
{
//do the more general thing:
// Problem. Trying to call itself:
someFunc(x);
}
}
有什么方法可以显式地告诉编译器要调用哪个重载(比如 someFunc<Concept1>(x)
不起作用),还是仅取决于传递的对象的类型?假设我无法将 x
转换为更通用的类型,并且更通用的函数/概念不知道这个更具体的函数/概念,因此他们不能用约束排除它。
编辑:这些函数应该在同一个(全局)命名空间中。
通常的解决方法是使用单独的辅助函数:
void somefunc(const Concept1 auto& x) {
// general stuff
}
void somefuncSpecific(const Concept1 auto& x) {
somefunc(x);
}
void someFuncSpecific(const MoreSpecificConcept auto& x)
{
if(...)
{
//do specific stuff
}
else
{
//do the more general thing:
somefunc(x);
}
}
另一个没有分离功能的解决方法是使用 if constexpr
:
void someFuncSpecific(const Concept1 auto& x)
{
if constexpr(MoreSpecificConcept<decltype(x)>)
{
if (...)
{
//do specific stuff
// skip the rest:
return;
}
}
//do the more general thing:
somefunc(x);
}
如果可能(主要取决于两个概念),另一种解决方法是创建仅满足 Concept1
但不满足 MoreSpecificConcept
:
的包装器
template <Concept1 T>
struct AsConcept1
{
T& t;
// operations to satisfy Concept1 (but not MoreSpecificConcept)
// using some_type = typename Concept1::some_type
// void bar() { t.bar(); }
// ...
};
然后你可能会做
void someFunc(const MoreSpecificConcept auto& x)
{
if (...) {
// do specific stuff
} else {
// do the more general thing:
someFunc(AsConcept1{x});
}
}
这是我的版本 Minimal Complete Verifiable Example
#include <iostream>
#include <type_traits>
template <typename T>
concept aritmetic = std::is_arithmetic_v<T>;
template <typename T>
concept real = std::is_floating_point_v<T>;
template<aritmetic T>
void foo(T x)
{
std::cout << __PRETTY_FUNCTION__ << " x + 1 = " << x + 1 << '\n';
}
#ifdef HAS_OVERLOAD
void foo(real auto x)
{
std::cout << __PRETTY_FUNCTION__ << " x / 2 = " << x / 2 << '\n';
}
#endif
int main()
{
foo(1);
foo(1.1);
return 0;
}
这是我的 idea how to fix it:
#include <iostream>
#include <type_traits>
template <typename T>
concept aritmetic = std::is_arithmetic_v<T>;
template <typename T>
concept real = std::is_floating_point_v<T>;
template<aritmetic T>
void foo(T x) requires (!real<T>)
{
std::cout << __PRETTY_FUNCTION__ << " x + 1 = " << x + 1 << '\n';
}
void foo(real auto x)
{
std::cout << __PRETTY_FUNCTION__ << " x / 2 = " << x / 2 << '\n';
}
int main()
{
foo(1);
foo(1.1);
return 0;
}
我觉得这个版本很好很干净:不需要额外的功能或者这个讨厌的if
。
(我正在学习概念和模板,所以如果我有什么非常错误的地方,请纠正我。)我有一个将概念作为参数的函数。我现在正试图重载这个采用更具体概念的函数。那会做“更具体的事情”或调用不太具体的功能。
template<typename T>
concept Concept1 = ...;
template<typename T>
concept MoreSpecificConcept = ...;
Concept1 <T> &&
...;
//...
void someFunc(const Concept1 auto& x)
{
//do general stuff
}
void someFunc(const MoreSpecificConcept auto& x)
{
if(...)
{
//do specific stuff
}
else
{
//do the more general thing:
// Problem. Trying to call itself:
someFunc(x);
}
}
有什么方法可以显式地告诉编译器要调用哪个重载(比如 someFunc<Concept1>(x)
不起作用),还是仅取决于传递的对象的类型?假设我无法将 x
转换为更通用的类型,并且更通用的函数/概念不知道这个更具体的函数/概念,因此他们不能用约束排除它。
编辑:这些函数应该在同一个(全局)命名空间中。
通常的解决方法是使用单独的辅助函数:
void somefunc(const Concept1 auto& x) {
// general stuff
}
void somefuncSpecific(const Concept1 auto& x) {
somefunc(x);
}
void someFuncSpecific(const MoreSpecificConcept auto& x)
{
if(...)
{
//do specific stuff
}
else
{
//do the more general thing:
somefunc(x);
}
}
另一个没有分离功能的解决方法是使用 if constexpr
:
void someFuncSpecific(const Concept1 auto& x)
{
if constexpr(MoreSpecificConcept<decltype(x)>)
{
if (...)
{
//do specific stuff
// skip the rest:
return;
}
}
//do the more general thing:
somefunc(x);
}
如果可能(主要取决于两个概念),另一种解决方法是创建仅满足 Concept1
但不满足 MoreSpecificConcept
:
template <Concept1 T>
struct AsConcept1
{
T& t;
// operations to satisfy Concept1 (but not MoreSpecificConcept)
// using some_type = typename Concept1::some_type
// void bar() { t.bar(); }
// ...
};
然后你可能会做
void someFunc(const MoreSpecificConcept auto& x)
{
if (...) {
// do specific stuff
} else {
// do the more general thing:
someFunc(AsConcept1{x});
}
}
这是我的版本 Minimal Complete Verifiable Example
#include <iostream>
#include <type_traits>
template <typename T>
concept aritmetic = std::is_arithmetic_v<T>;
template <typename T>
concept real = std::is_floating_point_v<T>;
template<aritmetic T>
void foo(T x)
{
std::cout << __PRETTY_FUNCTION__ << " x + 1 = " << x + 1 << '\n';
}
#ifdef HAS_OVERLOAD
void foo(real auto x)
{
std::cout << __PRETTY_FUNCTION__ << " x / 2 = " << x / 2 << '\n';
}
#endif
int main()
{
foo(1);
foo(1.1);
return 0;
}
这是我的 idea how to fix it:
#include <iostream>
#include <type_traits>
template <typename T>
concept aritmetic = std::is_arithmetic_v<T>;
template <typename T>
concept real = std::is_floating_point_v<T>;
template<aritmetic T>
void foo(T x) requires (!real<T>)
{
std::cout << __PRETTY_FUNCTION__ << " x + 1 = " << x + 1 << '\n';
}
void foo(real auto x)
{
std::cout << __PRETTY_FUNCTION__ << " x / 2 = " << x / 2 << '\n';
}
int main()
{
foo(1);
foo(1.1);
return 0;
}
我觉得这个版本很好很干净:不需要额外的功能或者这个讨厌的if
。