views:

489

answers:

6

This is similar to (but different from) this question.

Here is some simple test code to illustrate some weridness 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?

A: 

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

Daniel A. White
A: 

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

jeffamaphone
+3  A: 

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.

anon
I really wish that the Standard would at least require a diagnostic message during compilation of the unit containing the mismatch.
D.Shawley
I totally disagree - the constness of the int parameter is an implementation detail that has absolutely no effect on the caller. There's no need to clutter the interface with implementation details.
SCFrench
+1 to @SCFranch. Absolutely, putting "const" into the declaration just exposes useless implementation details
Johannes Schaub - litb
+15  A: 

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.

Michael Burr
+1, for me that falls into the category of "I understand the logic but that seems like it just contributes to making the language weirder".
JaredPar
There's definitely plenty of weirdness in C++...
Michael Burr
+1  A: 

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.

Uri
It does not matter to the caller because you are making a copy of the passed parameter. If the parameter was passed by reference, it would be different.
Dusty Campbell
A: 

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'

James Curran
I'm not confused ;-) My example doesn't have any pointers in it, I wanted to know why this technique worked on one compiler and not the other. Read the question I linked to or try the example yourself. It's a useful technique as it helps to catch errors in the function itself, but *should* make no difference at all for the caller.
Chris Huang-Leaver