繁体   English   中英

带有特定返回类型的函数类型的C ++模板函数

[英]C++ template function that takes a function type with specific return type

我正在用c ++中的模板做一些魔术,并且想尝试一些事情。

在这种情况下,我编写了一个朴素的通用列表实现,其中包含一个List Type和一个包含数据的ListElement Type。

现在,我已经编写了一个模板化的“ for each call”函数,该函数采用具有任意参数列表的列表中存储的类型的任意成员函数类型,并使用给定参数在列表中的每个元素上调用该成员函数:

template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
    for(ListElement * current = this->first; current != nullptr; current = current->next)
    {
        (current->value->*call)(args ...);
    }
}

问题是我无法“响应”被调用函数的返回值。 虽然我不想实现.map功能!

现在,我想实现一个“直到每次调用”,该调用针对列表中的值调用一个函数,直到调用返回“ true”,然后停止。 为此,我需要将插入为模板参数的函数限制为任何专门返回布尔值的函数。 我打字直到编译器停止抱怨并得到以下信息:

template<bool (*function), typename ... arguments>
void for_each_call_until(arguments ... args)
{
    for(ListElement * current = this->first; current != nullptr; current = current->next)
    {
        if((current->value->*function)(args ...)) break;
    }
}

这是怎么回事,这是正确的方法吗?如果不是,那么正确的方法是什么?

编辑:正如某些人建议使用std ::名称空间中的函数:在这些小型培训课程中,我尽量避免像瘟疫一样使用std :::好像我想使用std ::我不会写这些小小的标准实现我自己使用列表,向量或映射之类的东西,但使用std ::或boost ::

首先,这种方法不必要地限制了:

(current->value->*call)(args ...);

如果需要成员函数,则实际上只能执行少量操作。 如果来电者想做更多的事情,那就有点麻烦了。 相反,一般化并通过current->value作为第一个参数:

template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
    for(ListElement * current = this->first; current != nullptr; current = current->next)
    {
        call(current->value, args...);
    }
}

这适用于以前的所有情况-在此之前您可以通过&Class::mem传递而不是通过std::mem_fn(&Class::mem) -但现在您也可以传递任何可调用类型。


现在到您的主要问题。 您不必做任何其他事情。 只需使用call()的结果即可:

template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
    for(ListElement* current = this->first; current != nullptr; current = current->next)
    {
        if (call(current->value, args...)) {
            break;
        }
    }
}

而已。 如果用户提供的可调用对象没有返回上下文可转换为bool ,则会产生编译错误。 为什么只限于返回bool

如果确实需要bool ,则抛出一个静态断言:

template<typename function, typename ... arguments>
void for_each_call(function call, arguments ... args)
{
    static_assert(std::is_same<decltype(call(this->first->value, args...)), bool>::value, "Must be bool!");
    // rest...
}

注意:您可能想通过引用const来接受arguments... ,以避免大量复制。

从此开始,仅向您展示成员函数指针的工作方式

class Foo {
 public:
  bool test() { return true; }
};

/// The function takes a member function of a class T and its arguments.
template<typename T, typename... Args>
void for_each_call_until(bool (T::*member_function)(Args...),
                         Args&& ... args) {
  T obj;  // Instantiate an example object.
  bool rts = (obj.*member_function)(std::forward<Args>(args)...);
  if (rts == false) {  // Check for the result of the member function
    // close
  }
  // ...
}

您的功能可能类似于:

template<typename... Args>
void for_each_call_until(bool (ListElement::*member_function)(Args...),
                         Args&& ... args) {
  for ( /* iteration over pointers */ ) {
    bool rts = (current->*member_function)(std::forward<Args>(args)...);
    if (rts == false) {
      // break
    }
    // ...
}
}

一个简单的解决方案涉及使用部分专业化来强制编译错误:

#include <type_traits>
#include <utility>

template<typename T> struct is_bool;

template<> struct is_bool<bool> { typedef int value; };

template<typename function, typename ... arguments>
void for_each_call(function call, arguments && ... args)
{
    typedef decltype(call(std::forward<arguments>(args)...)) ret_type;

    typedef typename is_bool<ret_type>::value x;

    call(std::forward<arguments>(args)...);
}

bool foo(int, int) {}   // Compiles

// int foo(int, int) {}   // Does not compile

int main()
{
    for_each_call(foo, 4, 2);
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM