我是在msvc 2005中做到的。
typedef void (*cleanup_t)();
void func(cleanup_t clean)
{
cleanup_t();
}
为什么这会编译?而不是给我一个警告?好吧,它给了我一个未引用的形式参数警告,但最初我做了这个当干净在一个类没有没有未引用的形式参数时,这个代码给我带来了问题。
什么是cleanup_t();真的在做什么,重点是什么?现在为了笑,我尝试了int(),并且也有效。
答案 0 :(得分:12)
我认为这是一个表达式,其值为cleanup_t类型的默认值。换句话说,一个表达式返回一个返回void的函数的NULL指针。
在C / C ++中,没有副作用的表达式(这是 - 我认为)是有效的语句,就像你可以有这样的语句:
1 + 2;
这不是语法错误,但有些编译器可能会发出警告。它们通常不会为返回NULL值的无副作用表达式发出警告,或者只是变量名称,因为这种类型的表达式通常在宏中用于调试目的(如assert()宏)。
您可以将其视为调用cleanup_t
类型的默认构造函数。在C ++中添加了类似于内置类型(或其类型的typedef)的默认类似构造函数的语法,以便模板可以将作为模板参数传入的类型的项设置为默认值,同时仍允许模板类型参数为非用户定义的类型。可能还有其他原因,但我相信这是其中之一。
类似的东西:
template <class T>
class foo
{
T myT;
public:
foo() {
myT = T();
};
};
typedef void (*cleanup_t)();
class bar
{
};
int not_quite_a_cleanup_t_func()
{
return 1;
}
int main()
{
foo<int> intFoo;
foo<cleanup_t> cleanup_t_foo;
foo<bar> barFoo;
// here I'm going to harp on one of the things I don't like about C++:
//
// That so many things that look like function calls are not or that
// the parens cause subtle behavior changes.
//
// I believe this is the reason this question was posted to
// stackoverflow, so it's not too far off topic.
//
// Many of these things exist because of backwards compatibility with C or
// because they wanted to fit in new features without adding keywords or
// new reserved tokens or making the parser even more complex than it already
// is. So there are probably good rationales for them.
//
// But I find it confusing more often than not, and the fact that there
// might be a rationale for it doesn't mean I have to like it...
cleanup_t cleanup1(); // declares a function named cleanup1 that returns a cleanup_t
cleanup_t cleanup2 = cleanup_t(); // cleanup2 is a variable of type cleanup_t that
// is default initialized
cleanup_t* cleanup3 = new cleanup_t; // cleanup3 is a pointer to type cleanup_t that
// is initialized to point to memory that is
// *not* initialized
cleanup_t* cleanup4 = new cleanup_t(); // cleanup4 is a pointer to type cleanup_t that
// is initialized to point to memory that *is*
// initialized (using default intialization)
cleanup2 = cleanup_t( not_quite_a_cleanup_t_func); // explicit type conversion using functional notation
cleanup_t(); // the OP's problem
cleanup2(); // call the function pointed to by cleanup2
(*cleanup2)(); // same thing
class cleanup_class
{
cleanup_t cleanup5;
public:
cleanup_class() :
cleanup5() // class member default initialization
{ };
};
}
答案 1 :(得分:9)
它正在执行cleanup_t类型的默认初始化程序,以创建该类型的临时文件,然后从不实际使用该临时文件。
这很像构造函数调用,“MyClass c = MyClass();”的“MyClass()”部分,除了指针到函数类型实际上没有构造函数。当然在我的代码片段中,“MyClass()”不一定会创建一个临时的,因为它是一个初始化表达式。 “MyClass()。some_method();”中的“MyClass()”也许是一个更接近的类比。
“int()”是另一种说“int(0)”的方式,这是说“(int)0”的另一种方式,这是另一种说“0”的方式。再次,它分配给一个临时的,如果这是整个语句,那么临时是未使用的。
如果在GCC上使用-Wall编译问题中的代码,则会收到警告“语句无效”。执行此操作的人的代码可能意味着键入“clean();”,不会产生该警告,因为它当然会产生调用该函数的效果。切换警告的另一个原因,并正确地修复它们; - )