How to deal with parameter names shadowing methods? - c++

The code below, compiled with gcc 4.9 with -std=c++14 -Wshadow produces the following warning:
main.cpp:12:24: warning: declaration of ‘id’ shadows a member of 'this' [-Wshadow]
main.cpp:
#include <string>
class Foo
{
public:
Foo(std::string id);
const std::string& id() const noexcept;
private:
const std::string m_id;
};
Foo::Foo(std::string id) : m_id(id) {}
const std::string& Foo::id() const noexcept { return m_id; }
int main(int argc, char** argv) { return 0; }
The codebase I inherited contains a lot of such code. The naming convention the original authors chose (and I have to stick to) requires that getters are not prefixed with "get". Renaming parameters such as id just for the sake of getting rid of this warning sounds like a lot of work for nothing. At the moment I'm leaning towards adding a trailing underscore - it only has to be done in .cpp files so that ugliness won't reach public headers. Does anybody have any other ideas?

Related

Error binding properties and functions in emscripten

I'm trying to use emscripten to compile a c++ class and expose bindings. I'm running into an error from the compiler.
#include <emscripten/bind.h>
#include <emscripten/emscripten.h>
using namespace emscripten;
class MyClass {
private:
int _year;
int _month;
int _day;
public:
MyClass() { }
MyClass(int year, int month, int day);
int getMonth();
void setMonth(int);
int getYear();
void setYear(int);
int getDay();
void setDay(int);
bool isLeapYear();
int daysInMonth();
void increment();
void decrement();
};
EMSCRIPTEN_BINDINGS(my_sample_class) {
class_<MyClass>("MyClass")
.constructor<>()
.constructor<int, int, int>()
.function("getMonth", &MyClass::getMonth)
.function("increment", &MyClass::increment)
.function("decrement", &MyClass::decrement)
.property("year",&MyClass::getYear, &MyClass::setYear )
//.property("month", &MyClass::getMonth, &MyClass::setMonth )
//.property("day",&MyClass::getDay, &MyClass::setDay )
;
}
The compiler has no problems with the constructors or the function binding. I run into a problem with the property binding. I only have one uncommented to minimize the errors that I get back (they are just repeats of the same error but for different lines). Here are the errors that I'm getting back.
In file included from MyDate.cpp:1:
In file included from ./MyDate.h:2:
emscripten/bind.h:1393:26: error: implicit instantiation of undefined template 'emscripten::internal::GetterPolicy<int (MyClass::*)()>'
auto gter = &GP::template get<ClassType>;
^
./MyDate.h:37:6: note: in instantiation of function template specialization 'emscripten::class_<MyClass, emscripten::internal::NoBaseClass>::property<int (MyClass::*)(), void (MyClass::*)(int)>' requested here
.property("year",&MyClass::getYear, &MyClass::setYear )
^
emscripten/bind.h:569:16: note: template is declared here
struct GetterPolicy;
^
emscripten/bind.h:1399:33: error: implicit instantiation of undefined template 'emscripten::internal::GetterPolicy<int (MyClass::*)()>'
TypeID<typename GP::ReturnType>::get(),
^
emscripten\1.38.21\system\include\emscripten/bind.h:569:16: note: template is declared here
struct GetterPolicy;
^
2 errors generated.
shared:ERROR: compiler frontend failed to generate LLVM bitcode, halting
I've looked up binding examples and it appears I'm using the right syntax. Does any one have any idea of what I might be doing wrong?
Found the problem!
The getter functions must be marked as const to avoid these errors.
EX:
int getMonth() const;

When can symbol accessed from template be declared later [duplicate]

I am writing a simple logger class similar to QDebug, which has a template method that save data into QStringList. The code is here:
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
class Logger
{
public:
Logger();
~Logger();
template <typename V>
Logger &operator<<(V const &value);
private:
QStringList msg;
};
inline Logger::Logger():
msg(QString("INFO:"))
{}
inline Logger::~Logger()
{
QTextStream out(stderr);
out << msg.join("");
}
template <typename V>
inline Logger &Logger::operator<<(V const &value)
{
msg << log(value);
return *this;
}
inline QString log(QString const &value)
{
return value;
}
inline QString log(int const (&value)[20])
{
return QString("Array");
}
int main(int argc, char *argv[])
{
Logger c;
int a[20] = {};
c << QString("test") << a;
return 0;
}
However, this doesn't compile with GCC 4.8.3.
$ g++ -I/usr/include/qt4 -L/usr/lib64/qt4 -lQtCore -o test2 test2.cpp
test2.cpp: In instantiation of ‘Logger& Logger::operator<<(const V&) [with V = int [20]]’:
test2.cpp:50:29: required from here
test2.cpp:32:21: error: ‘log’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
msg << log(value);
^
test2.cpp:41:16: note: ‘QString log(const int (&)[20])’ declared here, later in the translation unit
inline QString log(int const (&value)[20])
Indeed, if I move inline QString log(int const (&value)[20]) to the beginning or put a forward declaration, it compiles and works. But what confuses me is that inline QString log(QString const &value) works without any problem:
$ ./test2
INFO:testArray
I notice that QHash relies on qHash function, which is similar in this case. QHash works pretty fine with user-defined key classes (except arrays, which can't be a function return type).
Why do they behave differently? What did I miss here?
Thank you for your help.
BTW: Would you please tell me what would be good keywords for this question. I've tried combinations of "specialiation" "template" "forward declaration" "QHash" and "user-defined types", but they don't work.
The name log is looked up twice. At the point of template definition, ordinary lookup is performed. It doesn't find anything, since log is not declared at this point.
Then, at the point of instantiation, only argument-dependent lookup is performed. When the parameter is of type QString, the global namespace is searched since QString is declared there, and so log(QString) is found. But the type int[] doesn't have any associated namespaces, so argument-dependent lookup has nothing to search and finds nothing. Hence the error.

Why does inlining my accessors break my code?

I am experiencing a strange issue where attempting to inline the accessors for my "Person" class causes the code to fail to compile.
The following code will compile and run successfully (Using Visual Studio 2012):
Person.h
#pragma once
#include <string>
using namespace std;
class Person
{
public:
Person(string name, int age = 0);
~Person(void);
// Accessors
string name(void) const;
int age (void) const;
private:
string m_name;
int m_age;
};
Person.cpp
#include "stdafx.h"
#include "Person.h"
Person::Person(string name, int age) :
m_name(name),
m_age (age )
{}
Person::~Person(void) {}
string Person::name(void) const
{
return m_name;
}
int Person::age(void) const
{
return m_age;
}
header_test.cpp
#include "stdafx.h"
#include <iostream>
#include "Person.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Person p("Joe");
cout << p.name() << endl;
return 0;
}
If I change my accessors to be defined as inline functions the code breaks.
Inlining the accessors in Person.h
// Accessors
inline string name(void) const;
inline int age (void) const;
Inlining the accessors in Person.cpp
inline string Person::name(void) const
{
return m_name;
}
inline int Person::age(void) const
{
return m_age;
}
Doing this produces the following errors:
1>header_test.obj : error LNK2019: unresolved external symbol "public: class std::basic_string,class std::allocator > __thiscall Person::name(void)const " (?name#Person##QBE?AV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##XZ) referenced in function _wmain
1>fatal error LNK1120: 1 unresolved externals
God that error message is cryptic... Thank you for all of that oh so useful information Microsoft/Visual Studio!
I know the inline keyword is just a "hint" to the compiler and probably has no real value here, but it still shouldn't break the code!
Why is this happening?
I am not a language lawyer, so I can't tell if the compiler behaviour is legitimate or not. Yet, I can explain what is happening.
When you are marking your functions inline, you are not hinting the compiler that it can inline this function. Since over 10 years compilers do not need your hint here. They know when to inline. Instead, what you do, you indicate the function definition to be local for every translation unit it is included in. For this definition should be available.
Effectively what you said is that name() definition should be local for every .cpp file, but you didn't make it available for every .cpp file! I still believe the compiler could give a warning here.
You need to define the function body in the header if you want to use the inline keyword. inline also does more than just give a hint to the compiler: it more or less shuts down the "one definition" rule* about functions being defined once and only once.
Furthermore, if you define class member functions inside the headers, ala
class Foo {
int bar() { return 5; }
};
they get "inlined" by default, so there's no reason to type the keyword out :-)
* Technically not, but for simplicity you can think of it as behaving that way. See the comment below by SergeyA.

Error: variable '*' has initializer but incomplete type and one other

I know there are a couple other questions on this specific question, but nothing that I can find on it seems to work, so I'm posting my specific code.
Here is the code:
#ifndef __MEMORY_TRACKER_H__
#define __MEMORY_TRACKER_H__
#include <unordered_map>
namespace cige
{
namespace memory
{
class CIGE_API MemoryTracker
{
protected:
typedef struct AllocRecord
{
size_t bytes;
std::string filename;
size_t line;
std::string func;
AllocRecord() :
bytes(0), line(0)
{ }
AllocRecord(size_t sz, const char* file, size_t ln, const char* fun) :
bytes(sz), line(ln)
{
if (file)
filename = file;
if (fun)
func = fun;
}
} AllocRecord;
std::string m_leakFileName;
bool m_dumpToConsole;
typedef std::unordered_map<void*, AllocRecord> AllocMap;
AllocMap m_allocationMap;
size_t m_totalAllocations;
bool m_recordEnable;
protected:
void reportLeaks();
MemoryTracker() :
m_leakFileName("CIGEMemory.log"), m_dumpToConsole(true), m_totalAllocations(0), m_recordEnable(true)
{ }
public:
void setReportFileName(const std::string& name)
{
m_leakFileName = name;
}
const std::string& getReportFileName() const
{
return m_leakFileName;
}
void setReportToConsoleOutput(bool b)
{
m_dumpToConsole = b;
}
bool getReportToConsoleOutput() const
{
return m_dumpToConsole;
}
void setRecordEnable(bool b)
{
m_recordEnable = b;
}
bool getRecordEnable() const
{
return m_recordEnable;
}
size_t getTotalMemoryAllocated() const
{
return m_totalAllocations;
}
void _recordAlloc(void* ptr, size_t sz, const char* file = nullptr, size_t ln = 0, const char* fun = nullptr);
void _recordDealloc(void* ptr);
~MemoryTracker()
{
reportLeaks();
}
static MemoryTracker& get();
};
}
}
#endif // __MEMORY_TRACKER_H__
I'm getting: variable 'cige::memory::CIGE_API cige::memory::MemoryTracker' has initializer but incomplete type at the line with the class declaration. I've looked all over and I cant find any answers that have fixed this issue.
I'm also having the error expected '}' or ',' or ';' before 'protected' at the line with protected, right above the struct.
Any help with either of these two errors would be appreciated.
EDIT: CIGE_API is defined in a separate file (which is included), as __declspec(dllexport).
EDIT2: I fixed my problem (see the answer below). It was basically just Code::Blocks derping out pretty bad.
Looks like CIGE_API is not defined. So compiler try to resolve it like variable declaration class Type Variable {initializer-list}, where Type is CIGE_API and Variable is MemoryTracker.
In other words, syntactically you're predeclaring CIGE_API type and creating variable of this type instead of defining a class.
The definition
class CIGE_API MemoryTracker { ... };
is not valid C++. I guess CIGE_API is a macro defined to an implementation specific extension, but you didn't include the corresponding header which defines that macro.
Ok I ended up fixing my own problem. Code::Blocks wasn't properly finding files that were in my project (about the third time this has happened).
In entirely unrelated news, does anyone know another cross-platform IDE that works well for C++? (I already know about Eclipse).

g++ 4.2: internal compiler error: in make_thunk, at cp/method.c:129

I asked this question already on http://www.cplusplus.com/forum/general/96128/ but to no avail.
does anybody experienced the same bug with g++ 4.2: internal compiler error: in make_thunk, at cp/method.c:129
I think it is not neccessary to include sample code. The respective code compiles without warnings and errors on several other newer g++ versions, as well as on clang++. It is simply correct and the bug was mentioned in the GCC's bugzilla (even several times, because it seems to recurr often), but no workaround was provided.
Please don't tell also to use a newer g++. I MUST compile it on the g++ shipped with Ubuntu Hardy, so I cannot change the compiler. Main development is done on Ubuntu Precise, but I need to keep it compatible to Hardy.
I have no idea what a thunk should be, I only suspect it has to do with covariants and/or multiple inheritance. Also I have several more similar structured header files, which all compile well, despite the only change is the name is the name of the class and I have no aim, to change that because of a compiler bug on Hardy.
Another fact is, it happens at include time.
In file included from /home/heiko/hgl/src/compiler/compilerprojectfactory.cpp:18:
/home/heiko/hgl/src/compiler/compilertype.h: In instantiation of 'HGL::Compiler::CompilerType<HGL::Vector2D, HGL::Compiler::CompilerBase>':
/home/heiko/hgl/src/compiler/compilervector2d.h:23: instantiated from here
/home/heiko/hgl/src/compiler/compilertype.h:22: internal compiler error: in make_thunk, at cp/method.c:129
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://gcc.gnu.org/bugs.html> for instructions.
For Debian GNU/Linux specific bug reporting instructions,
see <URL:file:///usr/share/doc/gcc-4.2/README.Bug
EDIT: Here the header which causes the bug:
#include "compilertype.h"
#include "vector2d.h"
namespace HGL {
class Vector2D;
namespace Compiler {
/**
#author Heiko Schäfer <heiko#rangun.de>
*/
class _LOCAL Vector2D : public Compiler::CompilerType<HGL::Vector2D> {
DISALLOW_COPY_AND_ASSIGN(Vector2D)
public:
Vector2D(float x, float y, int line);
using IType::operator=;
virtual operator HGL::Vector2D &() const throw(InvalidExpressionException);
protected:
virtual ~Vector2D();
void append(ISerializeable::BUFFER *dest, const HGL::IType *type) const;
};
}
}
Here the template:
#include "compilerbase.h"
#include "iproject.h"
#include "util.h"
namespace HGL {
namespace Compiler {
const IProject::VSTRUCT minReq = { HGL_MINREQ_MAJOR, HGL_MINREQ_MAJOR, HGL_MINREQ_MAJOR };
template<class Type, class Base = CompilerBase>
class _LOCAL CompilerType : public Type, public Base {
DISALLOW_COPY_AND_ASSIGN(CompilerType)
public:
using IType::operator=;
template<class Param>
inline CompilerType(const Param &p, bool b, int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) :
Type(p), Base(line, b) {
init(vs);
}
template<class Param>
inline CompilerType(const Param &p, int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) : Type(p), Base(line) {
init(vs);
}
inline CompilerType(bool b, int line, const IProject::VSTRUCT &vs = IProject::VSTRUCT())
: Type(), Base(line, b) {
init(vs);
}
template<class Param1, class Param2>
inline CompilerType(const Param1 &p1, const Param2 &p2, int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) :
Type(p1, p2), Base(line) {
init(vs);
}
template<class Param1, class Param2>
inline CompilerType(const Param1 &p1, const Param2 &p2, bool b, int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) : Type(p1, p2),
Base(line, b) {
init(vs);
}
inline CompilerType(int line,
const IProject::VSTRUCT &vs = IProject::VSTRUCT()) : Type(), Base(line) {
init(vs);
}
inline virtual void append(ISerializeable::BUFFER *dest, const IType *type) const {
Base::append(dest, type);
}
protected:
inline virtual ~CompilerType() {}
inline virtual void init(const IProject::VSTRUCT &vs) {
const_cast<IProject::VSTRUCT &>(vs) = std::max(vs, minReq);
CompilerBase::setMinRequiredVersion(vs, Type::getSerialID());
}
};
}
}
RESOLVED!
After digging in g++ 4.2's source code I found out that it needs to now about all types in the complete tree. g++ > 4.2 apparently doesn't need this.
So, the error was in a related class which had a template member with a forwarded specialization. I just included the header instead of forwarding and g++ 4.2 was happy.
Otherwise it is really a non-nice bug not to give an error, but this useless message.
A thunk or trampoline is a piece of code that is added in some implementations of dynamic dispatch to adapt the interface of the base virtual function with respect to the final overrider being used. As you mentioned it is commonly needed to adapt the this pointer in multiple/virtual inheritance (for bases listed after the first non-empty one) and to adapt the resulting pointer/reference with covariant return types.
The error indicates that it is a compiler bug. If you have to use that particular compiler you will need to work around the issue, and that will involve changing your design. You can try to limit the use of multiple/virtual inheritance, reorder the bases in the list or try to play around until you manage to get the compiler to digest that code somehow. If it is a problem when generating the adapter for a covariant return type, consider removing the covariant return and provide an overload (with a different name) that will return the covariant type (i.e. replace covariant return with a non-virtual function returning the most derived type and a virtual function that calls the previous and returns a reference to the base).
Other than those generic hints, without seeing the code you have and the implementation of the compiler there is little else to say.