是否可以获取内置标准运算符的函数指针?

Is it possible to get the function pointer of a built-in standard operator?

提问人:πάντα ῥεῖ 提问时间:7/15/2013 最后编辑:πάντα ῥεῖ 更新时间:5/9/2022 访问量:2964

问:

我想引用内置运算符的函数指针,但我不知道如何指定具体类型的重载。

我有以下模板类签名:

template<typename ParamsType, typename FnCompareType>
class MyAction
{
public:
    MyAction(ParamsType& arg0, ParamsType& arg1, FnCompareType& fnCpmpare) 
    : arg0_(arg0), arg1_(arg1), fnCompare_(fnCpmpare) {}

    bool operator()()
    {
        if((*fnCompare_)(arg0_,arg1_)
        {
            // do this
        }
        else
        {
            // do s.th. else
        }
    }

private:
    ParamsType& arg0_;
    ParamsType& arg1_;
    FnCompareType& fnCompare_;
}

并希望使用这样的语法:

void doConditional(int param1, int param2)
{
    MyAction<int,&::operator>=> action(param1,param2);
    if(action())
    {
        // Do this
    }
    else
    {
        // Do that
    }
}

但这并不能编译:

error: ‘::operator>=’ has not been declared

我能做些什么来引用这种固有的静态操作?

C++ 运算符

评论

0赞 Code-Apprentice 7/15/2013
ACTION_P1(MyAction,fnCompare) { ... }这甚至会编译吗?返回类型和参数类型在哪里?
0赞 πάντα ῥεῖ 7/15/2013
@MonadNewb 是的,确实如此!真正的定义甚至更加复杂。GoogleMock 通过模板参数列表延迟操作参数的类型。
0赞 Code-Apprentice 7/16/2013
感谢您删除 googlemock 的详细信息,以便让您的问题更清楚。为了将来参考,当你进行这种简化以达到问题的核心问题时,你应该做一个用普通 C++ 编译的例子,以便其他人可以复制和粘贴代码并按原样编译。
0赞 πάντα ῥεῖ 7/16/2013
@MonadNewb 我认为像素化学家的回答非常适合回答有关该主题的规范问题。应该改变什么才能使这个问题成为规范的问题,或者已经 s.th。类似的问?
0赞 Code-Apprentice 7/16/2013
是的,pixelchemist 给出了一个非常彻底和完整的答案。IMO,您应该修改您的示例代码,以便它可以在不依赖任何第三方库的情况下进行编译。从我阅读你的代码的方式来看,应该是一个函数名称。但是,我没有看到返回类型。此外,它的参数只有名称,没有类型。ACTION_P1

答:

9赞 fghj 7/15/2013 #1

您可以使用与 C++ 标准库中使用的相同的解决方案:

std::sort (numbers, numbers+5, std::greater<int>());

哪里大是

template <class T> struct greater : binary_function <T,T,bool> {
    bool operator() (const T& x, const T& y) const {return x>y;}
};

在你的情况下 http://www.cplusplus.com/reference/functional/greater_equal/

关于构建算子的参考。

您可以为任何类引用现有的运算符<(当然,如果它们不是私有的、受保护的,或者您的类/函数不是友元)。 但是 opeator<对于内置类型(bool、short、int、double)来说,它是不可能的参考。 事件,如果没有,请查看C++标准,您可以从我上面的文字中看到。

评论

0赞 πάντα ῥεῖ 7/15/2013
感谢!已经找到了如何使用它。对不起,我已经编辑了我的问题以获得一般答案,如果可以以某种方式引用这些运算符函数。
0赞 Code-Apprentice 7/15/2013
@g-makulik 标准库提供了包装大多数内置运算符的命名函数。
0赞 Code-Apprentice 7/15/2013
@g-makulik 我想我不明白你在寻找什么样的“一般答案”。您可以通过标准库给出的名称来引用“运算符函数”。
1赞 πάντα ῥεῖ 7/15/2013
@MonadNewb 再说一遍:我知道。但这些与“原始”函数指针有点不同,不是吗?这些是具有适当定义的结构,您需要一个实例来调用它们。operator()
0赞 fghj 7/15/2013
在 C++11 中,您可以改用 lambda 函数,而无需使用 opeator() 定义新结构
23赞 Pixelchemist 7/15/2013 #2

内置运算符

为什么你不能有它们的函数指针:

C++ 11, §13.6/1, [over.built]

表示第 5 条中定义的内置运算符的候选运算符函数在本子句中指定。这些候选函数参与 13.3.1.2 中所述的运算符重载解决过程,并且不用于其他目的

内置运算符(用于内置类型的运算符)不是真正的运算符函数因此,您不能让函数指针指向它们。您也不能使用语法调用它们。 它们只参与重载解析,但编译器会将它们直接转换为适当的 asm/machine 指令,而无需任何类型的“函数调用”。operator<(A,B)

解决此问题的方法:

user1034749 已经回答了这个问题,但为了完整起见:

该标准在§20.8 [function.objects]中定义了许多函数对象,即

  • 算术运算
  • 比较
  • 逻辑运算
  • 按位运算

函数对象是函数对象类型的对象。在人们希望将指向函数的指针传递给算法模板(第 25 条)的地方,接口被指定为接受函数对象。这不仅使算法模板能够与指向函数的指针一起使用,而且还使它们能够与任意函数对象一起使用。

C++11, §20.8.5, [比较]

  • equal_to
  • not_equal_to
  • 更大,更少
  • greater_equal
  • less_equal

这些是模板化的函数对象,它们在其函数中衰减为类似的运算符。它们可以用作函数指针参数。operator()

user1034749 是对的,我想声明:没有其他方法,这些在用法上完全等同于“原始”函数指针。给出的参考资料。

标准类类型运算符

您可以使用标准库运算符作为函数指针(以“实函数”的形式存在)。

但是您必须参考模板的相应实例。编译器将需要适当的提示来推断正确的模板。

这在 MSVC 2012 上对我有用,使用operator+std::basic_string

template<class Test>
Test test_function (Test const &a, Test const &b, Test (*FPtr)(Test const &, Test const &))
{
   return FPtr(a, b);
}

int main(int argc, char* argv[])
{
   typedef std::char_traits<char> traits_t;
   typedef std::allocator<char> alloc_t;
   std::basic_string<char, traits_t, alloc_t> a("test"), b("test2");
   std::cout << test_function<std::basic_string<char, traits_t, alloc_t>>(a, b, &std::operator+) << std::endl;
   return 0;
}

如果省略了 的模板参数,则此操作将失败(至少对于 MSVC 2012 而言)。test_function

评论

0赞 πάντα ῥεῖ 7/15/2013
这看起来很像这个问题的规范答案!
0赞 Lala5th 5/9/2022 #3

对 fghj 提供的解决方案的扩展,适用于赋值类型运算符,例如 / 等,是将它们包装得与标准变体类似。然后,您可以执行以下操作:+=-=

#include <iostream>

template <typename T>
struct assign_plus {
    void operator() const (T& a, const T& b){
        a += b;
    }
};

template <typename T>
struct assign_minus {
    void operator() const (T& a, const T& b){
        a -= b;
    }
};


template<template <class T> class O> requires requires(int& a, const int& b){
    { O<int>{}(a,b) };
}
void example(int& a, const int& b){
    O<int>{}(a,b);
}

int main(){
    int a = 5;
    int b = 6;
    example<assign_plus>(a,b);
    std::cout << a << "\n";
    example<assign_minus>(a,b);
    std::cout << a << "\n";
    return 0;
}

在给定兼容性的情况下,可以保留/删除约束。然后,还可以将这些约束扩展到有效的要求(例如,对于自定义类型)。c++20a += b