对于此代码
struct test {};
test f() { return test(); }
void print(test *x) {}
int main()
{
print(&f());
print(&test());
}
gcc-4.6发出两个“临时[-fpermissive]”错误的地址。这是在4.6中引入的,gcc-4.5可以编译它。
原因非常清楚并且有很好的记录。问题是它是一个遗留代码,为了编译,我们有使其工作,因此,围绕文件和/或部分代码执行#pragmas以使用-fpermissive编译它们。假设客户坚持不修改现有的代码(即用& f()或& test()调用print()的事实不能改变,一般不是源文件) 。换句话说,无论如何,将编译,唯一的选择是或多或少的痛苦。
所以问题是 - 是否有任何可能的解决方法可以使它在没有在许多地方做任务的情况下工作? -W标志,C ++技巧等
答案 0 :(得分:4)
我的意思是,无法更改使用& f()或& test()调用print()的事实。
如果您可以控制类型本身,则始终可以重载引用运算符operator&
,并从中返回this
。在一般情况下这不是一件好事,但考虑到你正在返回正确类型的正确指针,它是相当安全的。
如果涉及基类,那么它就会变得更加复杂。您需要使用虚拟运算符重载,层次结构中的每个类都需要单独实现它。
答案 1 :(得分:2)
您可以通过创建额外的print
重载来提供解决方法,该重载需要const&
:
void print( test const & t ) {
print(&t); // Assuming that the function is 'print( test const * )'
// a print function should not take a non-const pointer!
}
将来电者更改为:
print( f() );
这需要更改代码,但形式非常有限,因此可以接受。另请注意
答案 2 :(得分:2)
为什么不重写代码来完成编译器过去所做的事情而不抱怨?换句话说,将临时文件存储在临时(但可寻址)变量中。
struct test {};
test f() { return test(); }
void print(test *x) {}
int main()
{
test t1 = f();
test t2 = test();
print(&t1);
print(&t2);
}
这应该与旧编译器版本的行为相同。告诉客户新编译器要求您更改代码以明确编译器过去隐式执行的操作。
答案 3 :(得分:0)
我不清楚你对什么有多少控制,但下面的黑客似乎有效:
修改:最初有f
返回引用而不是副本。 DeadMG正确指出,一旦临时使用,就会导致未定义的行为,因此将f
恢复为返回副本。
struct test {};
const test & test_copy (const test &t) { return t; }
#define test() test_copy(test())
test f() { return test(); }
#define f() test_copy(f())
void print(const test *) {}
int main()
{
print(&f());
print(&test());
}
hack基本上是将你的临时转换为const引用,这样编译器会更快乐。它不应该普遍可用,它的唯一目的是关闭编译器。但是,它并没有真正解决客户代码或提供的API的任何潜在问题。您可以修复您的API,并且只针对某些客户使用黑客攻击:
struct test {};
test f() { return test(); }
void print(const test &) {}
#define CUSTOMER_NEEDS_HACK
#ifdef CUSTOMER_NEEDS_HACK
const test & test_copy (const test &t) { return t; }
#define test() test_copy(test())
#define f() test_copy(f())
void print(const test *t) { print(*t); }
#endif