g ++ 5.2 - 调用带有整数文字的模板参数包时的初始化警告

时间:2015-12-12 15:24:42

标签: c++ g++ c++14 clang++

看到this Meeting C++ 2015 lightning talk后,我尝试了这段代码

#include <iostream>
#include <utility>

template <typename Fun, typename... Param>
auto generic_bind(Fun fun, Param&&... param)
{
    return [fun, &param...] (auto&&... x)
    {
        return fun(std::forward<Param>(param)... , 
                   std::forward<decltype(x)>(x)...);
    };  
}

int demo(int a, int b, int c) { return a * b + c; }

int main()
{
    // does work with int variables
    int a = 11, b = 22, c = 33;
    auto f1 = generic_bind(demo, a); 
    auto f2 = generic_bind(f1, b);
    std::cout << f1(b, c) << f2(33); // both result in 275
}

main()正文更改为

     // does not work with int literals in g++ 5.2.0
     auto f1 = generic_bind(demo, 11); 
     auto f2 = generic_bind(f1, 22);
     std::cout << f1(22, 33) << f2(33);

clang++ -Wall两者都正常,但GNU g ++ 5.2创建了一个-Wuninitialized警告:

main.cpp: In function 'int main()':
main.cpp:14:42: warning: '<anonymous>' is used uninitialized in this function [-Wuninitialized]
int demo(int a, int b, int c) { return a * b + c; }
                                         ^
main.cpp:27:31: note: '<anonymous>' was declared here
  auto f2 = generic_bind(f1, 22);
                               ^
main.cpp:14:42: warning: '<anonymous>' is used uninitialized in this function [-Wuninitialized]
int demo(int a, int b, int c) { return a * b + c; }
                                         ^
main.cpp:26:36: note: '<anonymous>' was declared here
     auto f1 = generic_bind(demo, 11); 

并给出了意想不到的结果33(参见:Coliru live example)。哪个编译器在C ++ 14上是正确的?

1 个答案:

答案 0 :(得分:1)

该程序具有未定义的行为,因此任何事情都可能发生,因此可以说两个编译器都是正确的! GCC的警告是一个有用的线索,即使他们没有解释确切的问题也存在问题。

当您使用整数文字时,它会导致创建临时int对象,并且Params&&引用参数绑定到这些临时右值。然后你的lambda使用引用捕获,因此你返回的闭包包含对临时数的引用。

那些临时表演在完整表达结束时超出范围,即在致电generic_bind之后的分号。这意味着当您调用f1f2时,您会读取悬空引用,这是未定义的行为。

在原始代码中,Params&&参数绑定到自动变量abc,然后闭包包含对这些相同对象的引用,以及当您调用f1f2时,它们仍在范围内。所以原始代码没问题(尽管如果f1f2转移到更广泛的范围并且已经过了abc,那么您将拥有相同的代码问题)。