定义中而非声明中的 const 值参数真的是 C++ 吗?

发布于 2024-07-17 13:58:27 字数 1557 浏览 4 评论 0原文

这类似于(但不同于)这个问题< /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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

喜你已久 2024-07-24 13:58:27

这看起来像是 CC 中的编译器问题。 C++ 标准规定(在 13.1 可重载声明中):

仅在是否存在 const 和/或 volatile 方面有所不同的参数声明是等效的。 也就是说,在确定正在声明、定义或调用哪个函数时,将忽略每个参数类型的 const 和 volatile 类型说明符。

但是有 const/volatile 修饰符可以参与重载,正如标准随后不久提到的那样:

只有参数类型规范最外层的 const 和 volatile 类型说明符才会以这种方式被忽略; 隐藏在参数类型规范中的 const 和 volatile 类型说明符非常重要,可用于区分重载函数声明。

This looks like a compiler problem in CC. The C++ standard says (in 13.1 Overloadable declarations):

Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored when determining which function is being declared, defined, or called.

But there are const/volatile modifiers that can participate in overloading, as the standard mentions shortly afterwards:

Only the const and volatile type-specifiers at the outermost level of the parameter type specification are ignored in this fashion; const and volatile type-specifiers buried within a parameter type specification are significant and can be used to distinguish overloaded function declarations.

べ繥欢鉨o。 2024-07-24 13:58:27

编译器应忽略“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.

羁〃客ぐ 2024-07-24 13:58:27

我的理解是这是允许的,因为这对调用者来说没有什么区别。 它不是 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.

烟燃烟灭 2024-07-24 13:58:27

您的代码是正确的; 正如迈克尔·伯尔的回答所示,编译器存在问题。

以下两个函数声明是相同的:

void Print(int number);
void Print(const int number);  // Okay. Redeclaration of Print(int).

一般来说,大多数样式指南建议不要在函数声明中使用不必要的 const。 因此,在上面的示例中,首选第一个声明。 例如,请参见: https://abseil.io/tips/109

但是,只有第一个以下两个函数定义编译,因为第二个函数重新定义了第一个函数:

void Print(int number) {
  std::cout << number << std::endl;
}

void Print(const int number) {  // Error: Redefinition of Print(int).
  std::cout << number << std::endl;
}

这两个定义定义了相同的函数声明,Print(int) ,因此第二个由于单一定义规则而导致编译错误。 然而,第二个定义(带有 const 的定义)更清晰:它表明参数的值不能在函数内部更改,并防止未来的开发人员意外修改参数的值。 在这样一个简单的例子中,这可能并不重要,但一般来说,大多数风格指南都鼓励在函数定义中使用 const ; 请参阅上面的 Abseil 库链接。

总的来说,通常推荐的方法是避免在函数声明中使用不必要的 const,而是在函数定义中使用 const。 例子:

// Header file:
void Print(int number);

// Source file:
void Print(const int number) {
  std::cout << number << std::endl;
}

Your code is correct; there is a problem with the compiler as Michael Burr's answer indicates.

The following two function declarations are identical:

void Print(int number);
void Print(const int number);  // Okay. Redeclaration of Print(int).

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:

void Print(int number) {
  std::cout << number << std::endl;
}

void Print(const int number) {  // Error: Redefinition of Print(int).
  std::cout << number << std::endl;
}

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 with const) 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 of const 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 consts in function declarations, but to use consts in function definitions. Example:

// Header file:
void Print(int number);

// Source file:
void Print(const int number) {
  std::cout << number << std::endl;
}
长亭外,古道边 2024-07-24 13:58:27

我总是会在声明和定义上匹配 const。 这会减少任何问题,因为签名会匹配。

I would always match the const on both declaration and definition. This would reduce any problems because the signatures would match then.

往事随风而去 2024-07-24 13:58:27

constvoid func1(const int) 对函数没有任何影响,因为 int 是按值传递的——创建了 int 的副本,并且该副本仅在函数调用期间存在。 无论您是否更改该副本都没有任何影响。

您可能会对 void func2(const char*)const 很重要这一事实感到困惑。 但您必须认识到它与 void func3(char* const) 不同。 前者是指向的字符,不能改变; 在后者中,指针是(无关紧要的)“const”

The const is void 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*) the const is significant. But you have to recognized that is different from void 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'

飘然心甜 2024-07-24 13:58:27

请参阅 Alexandrescu 的 C++ 编码标准 #15。 按照他的说法,这应该有效。 const 防止函数的实现者更改输入变量。 IMO 变量应该在函数内保持常量。 如果您需要一个变量,请声明一个。 优化器会帮你去掉它。

int temp = a;

由于这在这里不起作用,我建议我的类在原型和实现中都使用 (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.

int temp = a;

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.

金兰素衣 2024-07-24 13:58:27

是的,const int 与 int 不同。

Yes, a const int is not the same as an int.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文