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

C++ template allows discard of const reference qualifier

本文关键字:引用 常量 许丢弃 C++      更新时间:2023-10-16

为什么编译这段代码?(用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 copyn";
        }
};
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关于通用参考的演讲)。

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

#include <functional>
#include <iostream>
#include <utility>
class C
{
public:
        C() {}
        C(const C&)
        {
                std::cout << "C copyn";
        }
};
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函数不按值获取。它应该通过引用(非常量常量)。