c++ - 将 lambda 包装为 std::function 会产生错误的结果(是模板参数推导的危险)

标签 c++ templates c++17

返回包装为 std::function 的某个 lambda 会产生错误的结果:

#include <functional>
#include <iostream>
#include <tuple>

template <typename T>
std::function<const T&()> constant(const T& c) {
  return [c]() noexcept -> const T&{ return c; };
}

template <typename T>
std::function<std::tuple<T>()> zip(const std::function<T()>& f) {
  return [f]() { return std::tuple{f()}; };
}

int main() {
    const auto good = [f = constant(1.0)]() { return std::tuple{f()}; };
    const auto bad = zip(constant(1.0));
    std::cout << "good: " << std::get<0>(good()) << std::endl;
    std::cout << "bad:  " << std::get<0>(bad()) << std::endl;
}

输出:

$ ./a.out
good: 1
bad:  6.95282e-310

这看起来像是未定义的行为。这是怎么回事?

最佳答案

#include <functional>
#include <type_traits>

template <typename T>
std::function<const T& ()> constant(const T& c)
{
    return [c]() noexcept -> const T& 
    { 
        // the captured variable is no longer a reference type!
        static_assert(std::is_same_v<decltype(c), std::remove_reference_t<const T&>>);
        return c; 
    };
}

int main()
{
    auto fn = constant(42);
    auto answer = fn();
}

关于c++ - 将 lambda 包装为 std::function 会产生错误的结果(是模板参数推导的危险),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68952789/

相关文章:

c++ - 使用智能指针制作多态容器的正确方法是什么?

c# - 文件移动——操作系统如何知道是更新主文件表还是复制和删除?

c++ - 在 C++ 中为链表创建复制构造函数/函数

c++ - C++ 上不同类型的实例化

c++ - 元组和总结

c++ - 创建并遍历模板化对象数组

c++ - 当用作非类型模板参数时,是否可以自动派生 std::array 的大小

c++ - 使用 C++ 模板作为返回类型/变量名

c++ - 为什么在使用 libc++ 时 sizeof( std::variant< char > ) == 8 而不是 2 (如 MSVC 的 STL 和 libstdc++)?

c++ - 是否可以反序列化(从原始内存块)没有默认构造函数的对象?