定义中而非声明中的 const 值参数真的是 C++ 吗?
这类似于(但不同于)这个问题< /a>.
下面是一些简单的测试代码,用于说明我在 Sun CC 中发现的一些怪异之处:
//---------------main.cpp
#include "wtc.hpp"
int main(int, char**)
{
testy t;
t.lame(99);
return 0;
}
//--------------wtc.hpp
#ifndef WTC_HPP_INCLUDED
#define WTC_HPP_INCLUDED
class testy
{
public:
void lame(int );
};
#endif
//---------------wtc.cpp
#include <iostream>
#include "wtc.hpp"
void testy::lame(const int a)
{
std::cout << "I was passed " << a << "\n";
}
//---------------makefile
#CXX=CC
CXX =g++
#CXXFLAGS= -g
CXXFLAGS= -g3 -Wall -Werror
OBJECTS=$(patsubst %.cpp,%.o,$(wildcard *.cpp))
all : $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $@ $^
.PHONY: clean
clean :
rm *.o
当使用 g++ 对其进行编译时,它会编译、链接并执行运行时所期望的操作。 您还可以添加 ++a; 在 testy::lame() 中,编译器会抱怨更改只读变量(因为它应该)。
但是,当我使用 CC 进行编译时,出现以下链接器错误:
CC -g -c -o main.o main.cpp
CC -g -c -o wtc.o wtc.cpp
CC -g -o all main.o wtc.o
Undefined first referenced
symbol in file
void testy::lame(int) main.o
ld: fatal: Symbol referencing errors. No output written to all
make: *** [all] Error 1
使用 nm 和 C++filt 检查目标代码,我发现 g++ 版本创建了一个 testy::lame(int) 符号,而 CC 创建 testy::lame(const int) ,因此出现链接器错误。
我在 Stroustrup 的书中查找了它,但找不到提到的这种技术(并不意味着它不存在!); 那么这真的是一个编译器错误,还是只是一个在除 Solaris 之外的其他地方都有效的 hack?
This is similar to (but different from) this question.
Here is some simple test code to illustrate some weirdness I have discovered with Sun CC:
//---------------main.cpp
#include "wtc.hpp"
int main(int, char**)
{
testy t;
t.lame(99);
return 0;
}
//--------------wtc.hpp
#ifndef WTC_HPP_INCLUDED
#define WTC_HPP_INCLUDED
class testy
{
public:
void lame(int );
};
#endif
//---------------wtc.cpp
#include <iostream>
#include "wtc.hpp"
void testy::lame(const int a)
{
std::cout << "I was passed " << a << "\n";
}
//---------------makefile
#CXX=CC
CXX =g++
#CXXFLAGS= -g
CXXFLAGS= -g3 -Wall -Werror
OBJECTS=$(patsubst %.cpp,%.o,$(wildcard *.cpp))
all : $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $@ $^
.PHONY: clean
clean :
rm *.o
When this was compiled using g++ it compiles, links and does what you would expect when run.
You can also add a ++a; in testy::lame() and the compiler will complain about changing a read-only variable (as it should).
However when I compile using CC, I get the following linker error:
CC -g -c -o main.o main.cpp
CC -g -c -o wtc.o wtc.cpp
CC -g -o all main.o wtc.o
Undefined first referenced
symbol in file
void testy::lame(int) main.o
ld: fatal: Symbol referencing errors. No output written to all
make: *** [all] Error 1
checking the object code with nm and C++filt, I find that the g++ version creates a
testy::lame(int) symbol, whereas CC creates testy::lame(const int) , hence the linker error.
I looked it up in Stroustrup's book, but can't find this technique mentioned (doesn't mean it's not there!); so is this really a compiler bug, or just a hack that works everywhere else but Solaris?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
这看起来像是
CC
中的编译器问题。 C++ 标准规定(在 13.1 可重载声明中):但是有
const
/volatile
修饰符可以参与重载,正如标准随后不久提到的那样:This looks like a compiler problem in
CC
. The C++ standard says (in 13.1 Overloadable declarations):But there are
const
/volatile
modifiers that can participate in overloading, as the standard mentions shortly afterwards:编译器应忽略“const int”参数中的“const”。 然而,至少可以说,声明和定义之间的差异是糟糕的风格。
The 'const' in the 'const int' parameter should be ignored by the compiler. However, the difference between the declaration and the definition is bad style, to say the least.
我的理解是这是允许的,因为这对调用者来说没有什么区别。 它不是 const 函数,而是参数,并且您在定义中进行添加。 因此,您实际添加的常量仅影响实现
请参阅此问题。
My understanding is that this is allowed because it makes little difference for the caller. It is not the function that is const, but rather a parameter, and you are making the addition in the definition. Thus, the const you actually added affects only the implementation
See this question.
您的代码是正确的; 正如迈克尔·伯尔的回答所示,编译器存在问题。
以下两个函数声明是相同的:
一般来说,大多数样式指南建议不要在函数声明中使用不必要的 const。 因此,在上面的示例中,首选第一个声明。 例如,请参见: https://abseil.io/tips/109
但是,只有第一个以下两个函数定义编译,因为第二个函数重新定义了第一个函数:
这两个定义定义了相同的函数声明,
Print(int)
,因此第二个由于单一定义规则而导致编译错误。 然而,第二个定义(带有const
的定义)更清晰:它表明参数的值不能在函数内部更改,并防止未来的开发人员意外修改参数的值。 在这样一个简单的例子中,这可能并不重要,但一般来说,大多数风格指南都鼓励在函数定义中使用 const ; 请参阅上面的 Abseil 库链接。总的来说,通常推荐的方法是避免在函数声明中使用不必要的 const,而是在函数定义中使用 const。 例子:
Your code is correct; there is a problem with the compiler as Michael Burr's answer indicates.
The following two function declarations are identical:
In general, most style guides recommend against using an unnecessary const in function declarations. So, in the example above, the first declaration is preferred. See for example: https://abseil.io/tips/109
However, only the first of the following two function definitions compiles, because the second one redefines the first one:
Both of these definitions define the same function declaration,
Print(int)
, so the second one causes a compilation error due to the One Definition Rule. However, the second definition (the one withconst
) is clearer: it indicates that the parameter's value cannot change inside the function and prevents a future developer from accidentally modifying the parameter's value. It may not matter much in such a trivial example, but in general, use ofconst
in function definitions is generally encouraged by most style guides; see the Abseil library link above.Overall, the generally recommended approach is to avoid using unnecessary
const
s in function declarations, but to useconst
s in function definitions. Example:我总是会在声明和定义上匹配 const。 这会减少任何问题,因为签名会匹配。
I would always match the
const
on both declaration and definition. This would reduce any problems because the signatures would match then.const
是void func1(const int)
对函数没有任何影响,因为 int 是按值传递的——创建了 int 的副本,并且该副本仅在函数调用期间存在。 无论您是否更改该副本都没有任何影响。您可能会对
void func2(const char*)
中const
很重要这一事实感到困惑。 但您必须认识到它与void func3(char* const)
不同。 前者是指向的字符,不能改变; 在后者中,指针是(无关紧要的)“const”The
const
isvoid func1(const int)
has no affect whatsoever on the function, since the int is passed by value --- a copy of the int is made, and that copy lives only as long as the function call. Whether or not you change that copy has no bearing on anything.You are probably confused by the fact that in
void func2(const char*)
theconst
is significant. But you have to recognized that is different fromvoid func3(char* const)
. In the former, it's the character pointed to that cannot change; in the latter, it's the pointer that is (irrelevantly) 'const'请参阅 Alexandrescu 的 C++ 编码标准 #15。 按照他的说法,这应该有效。 const 防止函数的实现者更改输入变量。 IMO 变量应该在函数内保持常量。 如果您需要一个变量,请声明一个。 优化器会帮你去掉它。
由于这在这里不起作用,我建议我的类在原型和实现中都使用 (const int a) 。 我非常喜欢使用适用于所有编译器的技术。
See C++ Coding Standards by Alexandrescu #15. This should work according to him. The const prevents the implementer of the function from changing the input variable. IMO the variable should remain const inside the function. If you need a variable, declare one. The optimizer will get rid of it for you.
Since this does not work here I am advising my class to use the (const int a) in both the prototype and implementation. I am a big fan of using techniques that work for all compilers.
是的,const int 与 int 不同。
Yes, a const int is not the same as an int.