为啥这个函子的 operator() 需要尾随 const 修饰符?

Posted

技术标签:

【中文标题】为啥这个函子的 operator() 需要尾随 const 修饰符?【英文标题】:Why does this functor's operator() need the trailing const modifier?为什么这个函子的 operator() 需要尾随 const 修饰符? 【发布时间】:2013-04-04 18:41:36 【问题描述】:

在我离开多年后,我又回到了 C++(或者,从技术上讲,Objective-C++),所以请多多包涵。我正在尝试使用模板来实现一个解决方案,否则它需要大量的剪切和粘贴代码。下面的摘录显示了这项工作的基本要点:

namespace 

    using vMAT::DOUBLE;
    using vMAT::SINGLE;
    using vMAT::INT8;
    using vMAT::UINT8;
    using vMAT::INT16;
    using vMAT::UINT16;
    using vMAT::INT32;
    using vMAT::UINT32;
    using vMAT::INT64;
    using vMAT::UINT64;

    typedef void (* swapFn)(void * vector, vDSP_Length vectorLength);

    // Functor used for template arguments.
    template <typename TypeA>
    struct swapbytes 
        swapFn fn;

        swapbytes()
        
            if      (sizeof(TypeA) == 8) fn = vMAT_byteswap64;
            else if (sizeof(TypeA) == 4) fn = vMAT_byteswap32;
            else if (sizeof(TypeA) == 2) fn = vMAT_byteswap16;
            else if (sizeof(TypeA) == 1) fn = NULL;
            else NSCAssert(NO, @"Oops!");
        

        void operator()(void * vector, vDSP_Length vectorLength) const
        // ..................................................... ^^^^^ Why?
        
            if (fn != NULL) fn(vector, vectorLength);
        
    ;

    template <typename TypeA, typename ClassB>
    void
    loadFromOperation(vMAT_MATv5NumericArray * self,
                      vMAT_MATv5ReadOperation * operation,
                      TypeA a,
                      ClassB b)
    
        swapbytes<TypeA> SwapA;
        long lenC = self.size[0] * sizeof(TypeA);
        TypeA * C = (TypeA *)malloc(lenC);
        long lenD = vMAT_Size_prod(self.size) * sizeof(ClassB);
        self.arrayData = [NSMutableData dataWithCapacity:lenD];
        self.arrayData.length = lenD;
        ClassB * D = (ClassB *)[self.arrayData mutableBytes];
        __block long idxD = 0;
        vMAT_Size123Iterator(self.size, ^(int32_t n, int32_t o, int32_t p) 
            [operation readComplete:C
                             length:lenC];
            if (operation.swapBytes)  SwapA((void *)C, lenC / sizeof(TypeA)); 
            for (int m = 0;
                 m < self.size[0];
                 m++) 
                D[idxD] = C[m];
                ++idxD;
            
        );
        free(C);
    



- (void)_load_miUINT8_mxDOUBLE_fromOperation:(vMAT_MATv5ReadOperation *)operation;

    loadFromOperation(self, operation, UINT8, DOUBLE);

我希望从以“为什么?”结尾的评论中可以看出我的问题是,为什么这里需要 const 声明?如果省略,编译器会抱怨在loadFromOperation 的主体中没有与SwapA(...) 处的调用站点匹配的方法签名。

如果SwapA 被明确声明为const,我会理解这一点,但事实并非如此。显然它可能是,因为它的操作不依赖于改变任何状态,但这不是重点。

虽然我对这段代码有另一双有用的眼睛,但我欢迎更精通 C++ 实践者可能愿意提供的任何风格或其他评论……

【问题讨论】:

^(...) ... 语法到底是什么?一些 lambda 扩展?哦等等,这是 Objective-C++? 是:Apple 的 LLVM 和 GCC 编译器中存在 Blocks 扩展。抱歉,我忘了这里有块。 【参考方案1】:

由块捕获的非__block变量,在创建块时按值复制到块中,并且在块内是const。即在块内,SwapA 的类型为 const swapbytes&lt;TypeA&gt;

【讨论】:

嘘!完美解释了,谢谢!我开始认为编译器中一定有一些晦涩的错误……我完全忽略了 C++ 可能如何与 Blocks 扩展进行交互。

以上是关于为啥这个函子的 operator() 需要尾随 const 修饰符?的主要内容,如果未能解决你的问题,请参考以下文章

验证函子的目标对象

Es6 函数式编程 MayBe函子的简单示例

进阶学习4:函数式编程FP——函子FunctorMayBe函子Either函子IO函子FolktalePointer函子Monad

JS函数式编程译5.2 函子 (Functors)

函数式夜点心:异步流程与 Task 函子

无法通过 std::ref() 调用带有 auto& 参数的 std::invoke()