C++ 模板允许丢弃 const 引用限定符

标签 c++ templates c++11 variadic-templates

为什么这段代码可以编译?(使用 g++ 和 clang++ 测试)

以下代码用于接受函数并从中创建转发 std::function 的工厂方法。如您所见,内部的 lambda 接受 const Arg& 参数并将它们转发给给定的函数。

main() 中,我使用 factory() 创建一个到 test_func() 的转发器,它接受一个非常量引用参数.我不明白的是为什么这不会产生关于从参数中丢弃 const 限定符的错误。

请注意,确实在 main() 中创建的类 C 的实例在传递时没有创建任何拷贝。

#include <functional>
#include <iostream>

class C
{
public:
        C() {}

        C(const C&)
        {
                std::cout << "C copy\n";
        }
};

int test_func(C& cref)
{
        return 0;
}

template<typename Ret, typename... Arg>
std::function<Ret (const Arg&...)> factory(Ret (*func) (Arg...))
{
        return [ func ] (const Arg&... arg) -> Ret {
                return (func)(arg...);
        };
}

int main() {
        auto caller = factory(test_func);
        C c;
        caller(c);
        return 0;
}

最佳答案

如评论中所述,您应该使用完美转发(请参阅 Scott Meyers 在 Universal reference 上的介绍)。

在你的情况下,它应该是:

#include <functional>
#include <iostream>
#include <utility>

class C
{
public:
        C() {}

        C(const C&)
        {
                std::cout << "C copy\n";
        }
};

int test_func(const C& )
{
        return 0;
}

template<typename Ret, typename... Arg>
std::function<Ret (Arg...)> factory(Ret (*func) (Arg...))
{
        return [ func ] (Arg&&... arg) -> Ret {
                return func(std::forward<Arg>(arg)...);
        };
}

int main() {
        auto caller = factory(test_func);
        const C c;
        caller(c);
}

请注意,我在您的 main() 中将 C c; 更改为 const C c;,并且我修改了 test_func。


如果你想避免创建拷贝,你必须确保 test_func 函数没有按值获取。它应该通过引用(const of non-const)。

关于C++ 模板允许丢弃 const 引用限定符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19654835/

相关文章:

c++ - 将数学函数作为方法的输入参数传递给C++

templates - Kendo Grid DetailTemplate,访问SubGrid值的条件表达式

c++ - 在 C++ 中返回一个对象

C++ 标准 I/O 和信号

c++ - 需要更改 C++ 控制台文本大小

c++ - C++中的大文件读取错误

C++ 编译时程序范围内的唯一编号

c++ - 将基础实例指针转换为派生实例指针是否合法? (该实例不是派生实例)

c++11 - 是否可以使用大括号初始值设定项来删除结构数组?

c++ - 类中带有 std::bind(func, this) 的 std::packaged_task