I am using an if constexpr to test the presence of a method in a class. If the method is not present, I wish to tell the user the function was ignored and he should implement it but it is not mandatory.
The idea is to give a message similar to #warning but the preprocessor is processed before the template thus this will never work.
Is there any compilation time feedback alternative that came with C++17? Or any planned for C++20?
Runnable example
template <typename State>
void callStateFunction(const State& state) {
if constexpr (false) {
state.method();
} else {
#warning The method State::method() was not implemented
}
}
Not a great solution, I suppose, but...
If your compiler activate all warnings (-Wall for g++ and clang++, by example), you can substitute the #warning row with something that generate a warning.
By example, an unused (maybe with a talking name) variable.
I've tried with
template <typename State>
void callStateFunction(const State& state) {
if constexpr (false) {
state.method();
} else {
int method_not_implemented[sizeof(State)];
}
}
and calling with a non-method value (callStateFunction(1), by example), I get
prog.cc: In instantiation of 'void callStateFunction(const State&) [with State = int]':
prog.cc:13:23: required from here
prog.cc:7:9: warning: unused variable 'method_not_implemented' [-Wunused-variable]
7 | int method_not_implemented[sizeof(State)];
| ^~~~~~~~~~~~~~~~~~~~~~
from g++ (head 11.0.0) and
prog.cc:7:9: warning: unused variable 'method_not_implemented' [-Wunused-variable]
int method_not_implemented[sizeof(State)];
^
prog.cc:13:4: note: in instantiation of function template specialization 'callStateFunction<int>' requested here
callStateFunction(1);
^
from clang++ (head 11.0.0)
I suggest that the unused variable depends from the template typename (State) otherwise, if I define a non-dependent variable as
int method_not_implement;
I get a warning from clang++
prog.cc:7:9: warning: unused variable 'method_not_implemented' [-Wunused-variable]
int method_not_implemented;
^
also without calling the function with a non-method object.
Related
If I have
namespace foo {
inline int bar() {
return 1119;
}
}
__attribute__((deprecated)) inline int bar() {
return 138;
}
in header.h and
#include "header.h"
#include <iostream>
int main() {
int x = bar();
int y = foo::bar();
std::cout << x << std::endl;
std::cout << y << std::endl;
}
in source.cpp, then
g++ source.cpp -o deprecated-test
results in
source.cpp: In function ‘int main()’:
source.cpp:5:17: warning: ‘int bar()’ is deprecated [-Wdeprecated-declarations]
int x = bar();
^
In file included from source.cpp:1:
header.h:7:40: note: declared here
__attribute__((deprecated)) int bar() {
^~~
source.cpp:5:17: warning: ‘int bar()’ is deprecated [-Wdeprecated-declarations]
int x = bar();
^
In file included from source.cpp:1:
header.h:7:40: note: declared here
__attribute__((deprecated)) int bar() {
(on Ubuntu 18.10 with g++ 8.2.0).
Why does the deprecated warning print twice?
Heading off some suggestions that would be unhelpful:
[[deprecated]]:
I know with C++14 on you can use the [[deprecated]] attribute, but I need to work with C++11.
Declaration vs. definition: The docs seem to imply it should be used with function declaration rather than definition, but
I need to define the functions inline in a header rather than declare in the header and define in source files; and
Trying this approach didn't stop the warning from printing twice anyway.
As per the documentation of GCC 8.2.0:
The deprecated attribute results in a warning if the function is used anywhere
in the source file. This is useful when identifying functions that are expected
to be removed in a future version of a program. The warning also includes the
location of the declaration of the deprecated function, to enable users to easily
find further information about why the function is deprecated, or what they
should do instead. Note that the warnings only occurs for uses...
There should be only one warning and not two. So this is a bug in GCC.
There is a related bug for Type attributes (rather than Function attributes) titled: C/C++ __attribute__((deprecated)) does not appear to wrap declarations as implied from the doc.
It has been confirmed as a bug.
I have a simple program containing the following code:
namespace nam
{
struct S{};
void f(S *){}
}
void f(nam::S *){}
int main()
{
nam::f(nullptr);
nam::S s;
f(&s);
return 0;
}
I expect that this will compile fine because I am calling f the second time without specifying namespace nam. However, upon compiling the code, I get this error:
$ g++ main.cpp -std=c++11 -Wall -Wextra
main.cpp: In function ‘int main()’:
main.cpp:14:9: error: call of overloaded ‘f(nam::S*)’ is ambiguous
f(&s);
^
main.cpp:7:6: note: candidate: void f(nam::S*)
void f(nam::S *){}
^
main.cpp:4:10: note: candidate: void nam::f(nam::S*)
void f(S *){}
Compiler and version:
$ gcc --version
gcc (Debian 5.3.1-14) 5.3.1 20160409
After trying this with different compilers, similar errors are returned. This seems to be a defined part of C++. I can't find anywhere on the internet where it says that calling a function with a struct in namespace nam as a parameter effectively implies using namespace nam; and requires ::f to remove ambiguity. I have 2 questions about this:
Where is this defined in the C++ standard?
Is there a good reason for this behavior?
Personally I like to avoid using namespace x; and similar. I want the compiler to give me an error when I don't specify a namespace. This behavior stops the compiler from doing so, and this means my code is inconsistent in places, because I occasionally forget to specify the namespace when calling functions like f that are not declared globally anywhere.
Your implementation of f(nam::S*) is outside of the namespace of 'nam'
change:
void f(nam::S *){}
to:
void nam::f(nam::S *){}
(or just move the enclosing namespace bracket) and all should be fine.
if your call to f(&s) in the current namespace was intentional then you need to specify this by changing the function call to
::f(&s)
As was said in the comments, this is due to argument-dependent lookup. I guess now I'll have to figure out now if I want to always specify the namespace in my code where this would make it unnecessary, or never specify it.
I stumbled across the below code and really found it complex to understand the nested macro and type casting in it.
Also when i tried to compile the code , i have encountered an error
Would need an explanantion of the below code.
why BEGIN_STATE_MAP and END_STATE_MAP set as labels in Motor.h , This is really new to me
Thanks in advance
Motor.h
// the Motor state machine class
class Motor : public StateMachine
{
public:
Motor() : StateMachine(ST_MAX_STATES) {}
// external events taken by this state machine
void Halt();
void SetSpeed(MotorData*);
private:
// state machine state functions
void ST_Idle();
void ST_Stop();
void ST_Start(MotorData*);
void ST_ChangeSpeed(MotorData*);
// state map to define state function order
BEGIN_STATE_MAP
STATE_MAP_ENTRY(ST_Idle)
STATE_MAP_ENTRY(ST_Stop)
STATE_MAP_ENTRY(ST_Start)
STATE_MAP_ENTRY(ST_ChangeSpeed)
END_STATE_MAP
// state enumeration order must match the order of state
// method entries in the state map
enum E_States {
ST_IDLE = 0,
ST_STOP,
ST_START,
ST_CHANGE_SPEED,
ST_MAX_STATES
};
};
#endif //MOTOR_H
what are BEGIN_STATE_MAP and END_STATE_MAP, This definition i found i really new,
BEGIN_STATE_MAP and END_STATE_MAP are the Macros defined in the below header file.
StateMachine.h
#ifndef STATE_MACHINE_H
#define STATE_MACHINE_H
#include <stdio.h>
#include "EventData.h"
struct StateStruct;
// base class for state machines
class StateMachine
{
public:
StateMachine(int maxStates);
virtual ~StateMachine() {}
protected:
enum { EVENT_IGNORED = 0xFE, CANNOT_HAPPEN };
unsigned char currentState;
void ExternalEvent(unsigned char, EventData* = NULL);
void InternalEvent(unsigned char, EventData* = NULL);
virtual const StateStruct* GetStateMap() = 0;
private:
const int _maxStates;
bool _eventGenerated;
EventData* _pEventData;
void StateEngine(void);
};
typedef void (StateMachine::*StateFunc)(EventData *);
struct StateStruct
{
StateFunc pStateFunc;
};
#define BEGIN_STATE_MAP \
public:\
const StateStruct* GetStateMap() {\
static const StateStruct StateMap[] = {
#define STATE_MAP_ENTRY(entry)\
{ reinterpret_cast<StateFunc>(entry) },
#define END_STATE_MAP \
{ reinterpret_cast<StateFunc>(NULL) }\
}; \
return &StateMap[0]; }
#define BEGIN_TRANSITION_MAP \
static const unsigned char TRANSITIONS[] = {\
#define TRANSITION_MAP_ENTRY(entry)\
entry,
#define END_TRANSITION_MAP(data) \
0 };\
ExternalEvent(TRANSITIONS[currentState], data);
#endif
EventData.h
#ifndef EVENT_DATA_H
#define EVENT_DATA_H
class EventData
{
public:
virtual ~EventData() {};
};
#endif //EVENT_DATA_H
While i tried to compile the code above.Below is the error that was encountered
Error
-------------- Build: Debug in StateMachine (compiler: GNU GCC Compiler)---------------
mingw32-g++.exe -Wall -fexceptions -g -pedantic -Wzero-as-null-pointer-constant -std=c++0x -Wextra -Wall -c C:\Users\xprk569\StateMachine\main.cpp -o obj\Debug\main.o
In file included from C:\Users\xprk569\StateMachine\main.cpp:2:0:
C:\Users\xprk569\StateMachine\Motor.h: In member function 'virtual const StateStruct* Motor::GetStateMap()':
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:\Users\xprk569\StateMachine\Motor.h:29:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Idle)
^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:\Users\xprk569\StateMachine\Motor.h:30:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Stop)
^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:\Users\xprk569\StateMachine\Motor.h:31:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Start)
^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:\Users\xprk569\StateMachine\Motor.h:32:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_ChangeSpeed)
^
C:\Users\xprk569\StateMachine\StateMachine.h:43:39: error: invalid cast from type 'int' to type 'StateFunc {aka void (StateMachine::*)(EventData*)}'
{ reinterpret_cast<StateFunc>(NULL) }\
^
C:\Users\xprk569\StateMachine\Motor.h:33:5: note: in expansion of macro 'END_STATE_MAP'
END_STATE_MAP
^
Process terminated with status 1 (0 minute(s), 0 second(s))
5 error(s), 0 warning(s) (0 minute(s), 0 second(s))
Can some please explain why is the macro written that way in Motor.h,
why is it declared like that in StateMachine.h and
why is the error being thrown ?
Thanks in Advance
It looks like this code depends on some nonstandard compiler extensions/errors.
To get it to compile (no idea if it will actually work) you need to replace the function names with full qualified member function pointers:
e.g.
BEGIN_STATE_MAP
STATE_MAP_ENTRY(&Motor::ST_Idle)
STATE_MAP_ENTRY(&Motor::ST_Stop)
STATE_MAP_ENTRY(&Motor::ST_Start)
STATE_MAP_ENTRY(&Motor::ST_ChangeSpeed)
END_STATE_MAP
After that, you need to figure out a way to overcome the non-conforming cast:
/tmp/gcc-explorer-compiler116314-75-1uiyu0/example.cpp: In member function 'virtual const StateStruct* Motor::GetStateMap()':
44 : error: invalid cast from type 'long int' to type 'StateFunc {aka void (StateMachine::*)(EventData*)}'
{ reinterpret_cast<StateFunc>(NULL) }\
^
83 : note: in expansion of macro 'END_STATE_MAP'
This cast is completely illegal. If I were you I would throw the code in the trash and rewrite - or use a proven state machine framework like boost meta state machine or boost statechart.
So you're quickly learning why Macros are no-nos in readable C++. If you get an error, you must expand the macro out to identify where the error is, also you cannot debug into them in most IDEs.
Anyway that said lets get to the expanding, their all the same error so we'll just look at the first one:
C:\Users\xprk569\StateMachine\Motor.h:29:9: note: in expansion of macro STATE_MAP_ENTRY
STATE_MAP_ENTRY(ST_Idle)
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the & ?)
{ reinterpret_cast<StateFunc>(entry) },
So this is complaining about line 29: STATE_MAP_ENTRY(ST_Idle) So lets expand that:
{ reinterpret_cast<StateFunc>(entry) },
Obviously this is bad syntax all together outside the scoping of BEGIN_STATE_MAP and END_STATE_MAP, so in debugging many Macros you'd also have to look at the scoping macros... sometimes they may not be clearly named or delineated unfortunately, but let's finish defining the line we got the error on first. What is this StateFunc we're trying to cast to?
typedef void (StateMachine::*StateFunc)(EventData *);
It's a pointer to a member function which returns a void and accepts an EventData *. And alarm bells should be going off. You cannot cast to that! ST_Idle is of the format: void (StateMachine::*)() so you cannot cast to void (StateMachine::*StateFunc)(EventData *). This is the same problem for all your functions passed into the macros none of them return a void and take an EventData*, so even if you fix the syntax, these reinterpret_casts will always return a pointer to a method which is invalid to call, meaning this entire block of Macros is pointless at best and toxic at worst. In the current state you may just as well use none of these Macros or if you need to define the method just do:
BEGIN_STATE_MAP
END_STATE_MAP
But if you were going to change your method declarations to something more like:
void ST_Idle(EventData*);
Then you'd need to use this syntax:
STATE_MAP_ENTRY(&Motor::ST_Idle)
If you're not down with the method pointers they are quite complex. I've typed up a quick example here: http://ideone.com/nL0HnQ Feel free to comment with questions.
EDIT:
To expand the Macros here we'll get:
public: // BEGIN_STATE_MAP
const StateStruct* GetStateMap() { // BEGIN_STATE_MAP
static const StateStruct StateMap[] = { // BEGIN_STATE_MAP
{ reinterpret_cast<StateFunc>(ST_Idle) } // STATE_MAP_ENTRY(ST_Idle)
{ reinterpret_cast<StateFunc>(ST_Stop) } // STATE_MAP_ENTRY(ST_Stop)
{ reinterpret_cast<StateFunc>(ST_Start) } // STATE_MAP_ENTRY(ST_Start)
{ reinterpret_cast<StateFunc>(ST_ChangeSpeed) } // STATE_MAP_ENTRY(ST_ChangeSpeed)
{ reinterpret_cast<StateFunc>(NULL) } // END_STATE_MAP
}; // END_STATE_MAP
return &StateMap[0]; } // END_STATE_MAP
So this set of macros will:
Set the scope to public
Declare the method GetStateMap
Declare StateMap statically local to GetStateMap, it will be an array of StateStructs
On the first call of the GetStateMap method StateMap will be initialized to contain method pointers to ST_Idle, ST_Stop, ST_Start, ST_ChangeSpeed, and NULL reinterpret_cast to StateFuncs
Define GetStateMap to return the StateMap array
I would like to use g++ and -Werror, so I have now to disable warnings for 3rd-party libraries I have no control of. The solution provided by http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html works very well, allowing simply to wrap the includes of 3rd party headers with pragmas. Unfortunately, that did no longer work for me in a certain setup where templates are involved. I created the following minimal example of where this approach did not work as expected:
Source file main.cpp
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "hdr.hpp"
#pragma GCC diagnostic error "-Wunused-parameter"
int main() {
return mytemplatefunc(2) + mystandardfunc(3); // will print ONLY ONE warning
}
and the header hdr.hpp
template<typename T>
int mytemplatefunc(T t) {
return 42;
}
int mystandardfunc(int i) {
return 53;
}
compiled using Makefile
CPPFLAGS+=-Wunused-parameter -Werror
main: main.cpp
will produce the following compiler error
g++ -Wunused-parameter -Werror main.cpp -o main
In file included from main.cpp:3:
hdr.hpp: In instantiation of ‘int mytemplatefunc(T) [with T = int]’:
main.cpp:29: instantiated from here
hdr.hpp:2: error: unused parameter ‘t’
make: *** [main] Error 1
shell returned 2
Note that explicit instantiation in main.cpp directly after including the header did not work, and wrapping the call to the template function in main.cpp did not work either. What was puzzling that putting #pragma GCC diagnostic ignored "-Wunused-parameter" in front of the main function silenced the compiler, whilst then adding #pragma GCC diagnostic error "-Wunused-parameter" at the very end of the file caused the compiler to produce the error again. How to solve this puzzle?
(Note, there are dozens of threads about this pragma, but I could not find anyone
that involved such a setup)
The issue is that the instantiation of the template is compiled when you use it, not when it is parsed by the compiler in the header file so it will not issue the warning until it replaces T by int and parses it as a regular function outside the context of the pragma silencing.
The usual way to indicate that you don't intend to use a parameter is to not give it a name:
template<typename T>
int mytemplatefunc(T /* t */)
{ return 42; }
int mystandardfunc(int /* i */)
{ return 53; }
Presently, I am using the following function template to suppress unused variable warnings:
template<typename T>
void
unused(T const &) {
/* Do nothing. */
}
However, when porting to cygwin from Linux, I am now getting compiler errors on g++ 3.4.4 (On linux I am 3.4.6, so maybe this is a bug fix?):
Write.cpp: In member function `void* Write::initReadWrite()':
Write.cpp:516: error: invalid initialization of reference of type 'const volatile bool&' from expression of type 'volatile bool'
../../src/common/Assert.h:27: error: in passing argument 1 of `void unused(const T&) [with T = volatile bool]'
make[1]: *** [ARCH.cygwin/release/Write.o] Error 1
The argument to unused is a member variable declared as:
volatile bool readWriteActivated;
Is this a compiler bug or a bug in my code?
Here is the minimal test case:
template<typename T>
void unused(T const &) { }
int main() {
volatile bool x = false;
unused(!x); // type of "!x" is bool
}
The actual way of indicating you don't actually use a parameter is not giving it a name:
int f(int a, float) {
return a*2;
}
will compile everywhere with all warnings turned on, without warning about the unused float. Even if the argument does have a name in the prototype (e.g. int f(int a, float f);), it still won't complain.
I'm not 100% sure that this is portable, but this is the idiom I've usually used for suppressing warnings about unused variables. The context here is a signal handler that is only used to catch SIGINT and SIGTERM, so if the function is ever called I know it's time for the program to exit.
volatile bool app_killed = false;
int signal_handler(int signum)
{
(void)signum; // this suppresses the warnings
app_killed = true;
}
I tend to dislike cluttering up the parameter list with __attribute__((unused)), since the cast-to-void trick works without resorting to macros for Visual C++.
It is a compiler bug and there are no known work arounds:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42655
It is fixed in v4.4.
In GCC, you can define a macro as follows:
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*#unused#*/ x
#else
# define UNUSED(x) x
#endif
Any parameters marked with this macro will suppress the unused warning GCC emits (and renames the parameter with a prefix of UNUSED_). For Visual Studio, you can suppress warnings with a #pragma directive.
The answer proposed by haavee (amended by ur) is the one I would normally use:
int f(int a, float /*epsilon*/) {
return a*2;
}
The real problem happens when the argument is sometimes but not always used in the method, e.g.:
int f(int a, float epsilon) {
#ifdef LOGGING_ENABLED
LOG("f: a = %d, epsilon = %f\n", a, epsilon);
#endif
return a*2;
}
Now, I can't comment out the parameter name epsilon because that will break my logging build (I don't want to insert another #ifdef in the argument list because that makes the code much harder to read).
So I think the best solution would be to use Tom's suggestion:
int f(int a, float epsilon) {
(void) epsilon; // suppress compiler warning for possibly unused arg
#ifdef LOGGING_ENABLED
LOG("f: a = %d, epsilon = %f\n", a, epsilon);
#endif
return a*2;
}
My only worry would be that some compilers might warn about the "(void) epsilon;" statement, e.g. "statement has no effect" warning or some such - I guess I'll just have to test on all the compilers I'm likely to use...