gpt4 book ai didi

c++ - 如何根据参数的调用运算符参数或存在来重载模板函数?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:37:47 25 4
gpt4 key购买 nike

注意:我使用的是 VS2013,因此可用的 C++11 功能有限。

我在重载模板函数时遇到问题,具体取决于参数类型是否可调用,理想情况下,参数是否与特定模式匹配。

这是一个非常简化的代码示例,我的问题是如何实现 update_callabe() 重载:

template< class T, class... Args >
void update_callable( const std::vector<T>& objects, Args&&... args ); // 1: How to implement this?

template< class T, class... UpdateArgs>
class Controller
{ //...
virtual void update( T&, UpdateArgs... args ) = 0;
public:
template< class IterBegin, class IterEnd, class... Args >
void update_batch( IterBegin first, IterEnd last, Args&&... args )
{
std::for_each( first, last, [&]( T& object ){ update(object, args...); }
}
//...
};

template< class T, class... UpdateArgs >
class Group
{
public:
using ControllerType = Controller<T,UpdateArgs...>;

void add( ControllerType& controler ) { /* ... */ m_controllers.emplace_back( &controller ); }

template< class... Args >
void update( Args&&... args )
{
update_callable(m_objects, std::forward<Args>(args)); // 2
for( auto* controller : m_controllers )
{
controller->update_batch( begin(m_objects), end(m_objects), std::forward<Args>(args)); // 3
}
}

private:
std::vector<T> m_objects;
std::vector<ControllerType*> m_controllers;
//...
};

一个。 我想通过 update_callabe() 重载(按优先顺序)实现什么:

  1. 如果 T 可以使用 Args 参数调用,则使用参数调用所有 T 对象。
  2. 如果 T 不能用 Args 参数调用,则什么也不做。

B.这对我来说没问题,但理想情况下,我希望 update_callabe() 重载遵循这些规则(按优先顺序):

  1. 如果 T 可以使用 Args 参数调用,则使用参数调用所有 T 对象。
  2. 如果 T 可以不带参数调用,则不带参数调用所有 T 对象。
  3. 如果 T 不能使用 Args 参数或 NO 参数调用,则什么也不做。

我尝试过使用 enable_if、条件和一些高级技术,但我(还)不是专家,所以我无法正确表达这一点。

关于此处示例的一些注释:

  • 这是一个简化的例子,我没有尝试编译它,但它接近我的代码;
  • (2) 基本上,如果对象的类型提供一个,我们想调用存储对象的默认更新,“默认更新”在这里意味着调用运算符带有来自更新上下文的参数,或者没有参数,如果类型不需要它们;
  • (3) “ Controller ”对象有第二个更新循环,可以从外部操作存储的对象;

最佳答案

当我想要if/else if/else - 编译时的类似行为,我使用这样的技巧:

template <unsigned int N>
struct priority_helper
: public priority_helper<N-1> {};

template <>
struct priority_helper<0U> {};

template <unsigned int N>
using priority = int priority_helper<N>::*;

constexpr priority<0> by_priority{};

template <typename Arg>
auto do_thing_detail(Arg&& arg, priority<1>)
-> typename std::enable_if<cond1<Arg>::value>::type
{ /*...*/ }
template <typename Arg>
auto do_thing_detail(Arg&& arg, priority<2>)
-> typename std::enable_if<cond2<Arg>::value>::type
{ /*...*/ }
template <typename Arg>
void do_thing_detail(Arg&& arg, priority<3>)
{ /*...*/ }

template <typename Arg>
void do_thing(Arg&& arg)
{ do_thing_detail(std::forward<Arg>(arg), by_priority); }

这也适用于使用更简单的类型 priority_helper<N>*而不是 int priority_helper<N>::* ,然后是 N 的较大值将是首选的重载,因为指向派生的指针比指向基的指针更具体。通过使用指向成员的指针,隐式转换和重载首选项会反过来(基成员指针转换为派生成员指针)。

所以对于你的问题,在定义 priority<N> 之后如上...

template < class T, class... Args >
auto update_callable_detail(
priority<1>,
const std::vector<T>& objects,
Args&& ... args )
-> decltype(std::declval<const T&>()(std::forward<Args>(args)...), void())
{
for ( const T& obj : objects )
obj( std::forward<Args>(args)... );
}

template < class T, class... Args >
auto update_callable_detail(
priority<2>,
const std::vector<T>& objects,
Args&& ... )
-> decltype(std::declval<const T&>()(), void())
{
for ( const T& obj : objects )
obj();
}

template < class T, class... Args >
void update_callable_detail(
priority<3>,
const std::vector<T>&,
Args&& ... )
{
}

template < class T, class... Args >
void update_callable( const std::vector<T>& objects, Args&& ... args )
{
update_callable_detail( by_priority, objects, std::forward<Args>(args)... );
}

在这种情况下,直接在重载声明中使用 SFINAE 似乎更简单,而不是对 std::result_of 做任何事情。 (特别是因为 result_of 的 C++11 要求不如 C++14 版本有用)。每当推导参数 TArgs导致 decltype 中的非法表达式,该重载在重载决议期间被抛出。

关于c++ - 如何根据参数的调用运算符参数或存在来重载模板函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24495334/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com