【问题标题】:Can I call directly operator() without creating a temporary object?我可以直接调用 operator() 而不创建临时对象吗?
【发布时间】:2013-05-04 18:22:14
【问题描述】:

我有以下实用函数将给定的字符串转换为整数。

class convertToInt:public std::unary_function<const char*, int>
{

        public:
                int operator()(const char* cNumber)
                {
                        try
                        {
                                int result = boost::lexical_cast<int>(cNumber);
                                return result;
                        } catch ( boost::bad_lexical_cast& error)
                        {
                                std::cerr << "Error in converting to number "<< error.what() << std::endl;
                                return -1;
                        }
                }

};

当我想实际使用这个实用功能时,我必须执行以下操作。

  convertToInt cStrToInt;
  int iNumberToCheck = cStrToInt(argv[1]);

我只是想知道,有没有办法,我可以直接调用

int iNumberToCheck = convertToInt(argv[1]);

【问题讨论】:

  • int iNumberToCheck = convertToInt()(argv[1]); ???
  • 谢谢老兄。欣赏它。
  • 请注意,这仍然会创建一个临时对象,因为实际上“convertToInt()”会创建一个 convertToInt 对象。因此创建全局函数对象的效率不会降低。

标签: c++ boost stl


【解决方案1】:

不,它是一个成员函数,需要一个对象才能调用它。您可以改用未命名的临时文件:

int iNumberToCheck = convertToInt()(argv[1]);

【讨论】:

  • 您可能想提到临时对象的成本为 0,并启用了轻度优化。由于临时没有状态,编译器将优化掉实例。
  • 谢谢hmjd。欣赏它。
【解决方案2】:

您可以将函数设为静态,这样它就不需要实例。调用必须有范围。

您还可以创建临时变量作为较大表达式的一部分(而不是使用命名变量),这可能看起来效率较低,但实际上可能已被您的编译器优化为相同的东西。

编辑添加:static 不适用于 operator(),因此您需要重新设计才能使用该选项。

【讨论】:

  • 创建staticoperator(...)合法吗?
  • @NikBougalis 不,不是,当我第一次写答案时,我错过了这个函数实际上是 operator() 。已更正。
【解决方案3】:

如果你知道调用点的函子的名字,那你为什么不把它变成一个函数呢?

int convertToInt(const char* cNumber)
{
    /*...*/
}

int iNumberToCheck = convertToInt(argv[1]);

【讨论】:

  • 如果你已经把它作为一个函数对象得到了(因为你将它传递给需要一个函子的东西,或者因为它必须是虚拟的,或者其他一些原因),为什么要重复代码在另一个函数中?
【解决方案4】:

只需创建一个静态初始化的全局变量,这有助于避免the static initialization order fiasco。静态初始化要求类是聚合类型。只需使用大括号来初始化它:

struct convertToIntF
{
    int operator()(const char* cNumber) const
    {
        try
        {
            int result = boost::lexical_cast<int>(cNumber);
            return result;
        } 
        catch ( boost::bad_lexical_cast& error)
        {
            std::cerr << "Error in converting to number "<< error.what() << std::endl;
            return -1;
        }
    }
};

convetToIntF converToInt = {};

现在,如果函数对象存储状态或继承自非聚合类,这将不起作用。然而,在 C++11 中,编写一个可以静态初始化任何默认可构造函数对象的适配器相当简单:

template<class F>
struct static_
{
    template<class... T>
    auto operator()(T && ... x) const -> decltype(F()(std::forward<T>(x)...))
    {
        static F f;
        return f(std::forward<T>(x)...);
    }
};

然后可以这样初始化:

static_<convetToIntF> converToInt = {};

【讨论】:

  • 小心。这很好,但即使是适度的更改也可能使总体假设无效并破坏程序(在 C++11 的情况下,静默)。另外,您通过要求 this 排除了函数对象的许多有趣行为。
  • @jerry 在 C++03 中,它会因编译错误而中断。在 C++11 中,编写一个可以静态初始化任何默认可构造函数对象的适配器相当简单(在 C++03 中也可以,但不是很简单)。
【解决方案5】:

在这个非常简单的情况下,匿名对象可能会正常工作,正如其他人所指出的那样。但是,如果您有一个更复杂的带有状态的类,请考虑单例模式:

class SingletonFunctor
{
    private:

        // some private state

        // for a hybrid approach, the constructor could be public
        SingletonFunctor()
        {
            // initialize state
        }

     public:

        static const SingletonFunctor& GetSingleton()
        {
            static const SingletonFunctor _singleton;

            return _singleton;
        }

        SomeType operator() (SomeOtherType param) const
        {
            // do something interesting
        }            
};

int main (void)
{
    SomeType firstVal = SingletonFunctor::GetSingleton()(SomeOtherType());

    // ...
    // later

    // no need to instantiate another object
    SomeType secondVal = SingletonFunctor::GetSingleton()(SomeOtherType());
}

如果你改变状态,请小心这种模式,它可能会出现与全局变量相同的问题(尤其是多线程)。

【讨论】:

    猜你喜欢
    • 2017-05-27
    • 2011-08-17
    • 2014-05-02
    • 1970-01-01
    • 2011-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多