I would like to create a compile-time error in my C++ code with a custom error message. I want to do this for a couple of reasons:
to force compilation to fail while I'm working on new features which haven't been implemented yet. (compile time ! TODO reminder)
to create a more readable error when attempting to implement an unsupported template specialization.
I'm sure there is a trick to doing this but I cant find a resource explaining the method. I would wrap the code in a #define of the form COMPILE_FAIL("error message");
Thanks
D
Use #error:
#error "YOUR MESSAGE"
This produces an error from the preprocessor. If you want to detect an error at a later stage (e.g. during template processing), use static_assert (a C++11 feature).
Look into static_assert.
Example:
#include <iostream>
#include <type_traits>
template<typename T>
class matrix {
static_assert(std::is_integral<T>::value, "Can only be integral type");
};
int main() {
matrix<int*> v; //error: static assertion failed: Can only be integral type
}
To force a compiler error (GCC, Clang style):
#error "You ain't finished this yet!"
Related
Please considere the following code-snippet:
#include <iostream>
void print(auto arg) {
std::cout << arg << std::endl;
}
int main() {
print("Hi");
return 0;
}
As you can see here (https://godbolt.org/z/2GSrXs) using GCC the code compiles and runs fine.
As you can see here (https://godbolt.org/z/rtR6w9) using Visual C++ the code does not compile and results in the error message:
<source>(3): error C3533: a parameter cannot have a type that contains 'auto'.
It seems to me that this feature has not jet been implementet in Visual C++?
Additionally I was not able to find the compiler feature in the following list:
https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=vs-2019. So I am not sure if the Microsoft developer have the feature on their ToDo List?
Functions receiving auto is a C++20 feature. It must be enabled with /std:latest. However, MSVC only has partial support for this syntax at this time, so not all declaration using this feature will work.
GCC has supported auto in function parameters since early C++14 days as an extension.
You can read more about this C++20 feature reading P1141R2: Yet another approach for constrained declarations
Remaining in C++14 standard, you can use the following lambda instead of your function:
auto print = [](auto arg) {
std::cout << arg << std::endl;
};
I'm trying to figure out how to use the Trompeloeil library with C++11. With this example, I've run into a huge amount of build errors, and I can't understand why.
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <rapidcheck.h>
#include <rapidcheck/state.h>
#include <trompeloeil.hpp>
#include "../../../include/Orion.h"
#include "../../../include/optionCheckerFileHandler.h"
class mock{
public:
MAKE_MOCK1(getFileParams, int(int));
};
TEST_CASE( "Factorials are computed", "[factorial]" ) {
using trompeloeil::_; // wild card for matching any value
using trompeloeil::gt; // greater-than match
mock m;{
REQUIRE_CALL_V(m, getFileParams(1)).RETURN(0);
}
}
There are a massive amount of build errors, but the ones that stand out to me are the following:
In file included from /home/adny/tortoiseSoftworks/software/gamedev/tortoiseGamedev/test/testing/src/main.cpp:5:0:
/home/adny/tortoiseSoftworks/software/gamedev/tortoiseGamedev/test/testing/src/main.cpp: In function ‘void ____C_A_T_C_H____T_E_S_T____0()’:
/home/adny/tortoiseSoftworks/software/gamedev/tortoiseGamedev/test/testing/lib/trompeloeil/include/trompeloeil.hpp:4727:3: error: ‘class std::unique_ptr<trompeloeil::expectation>’ has no member named ‘handle_return’
handle_return(
as well as
/home/adny/tortoiseSoftworks/software/gamedev/tortoiseGamedev/test/testing/lib/trompeloeil/include/trompeloeil.hpp:3891:7: error: static assertion failed: RETURN missing for non-void function
static_assert(valid_return_type, "RETURN missing for non-void function");
If somebody could help me make sense of these, it'd be much appreciated. I can provide the full build errors on request
Do you use C++ 11? Why do you use REQUIRE_CALL_V?
In fact you are using the C++14 syntax with the C++11 macro.
See https://github.com/rollbear/trompeloeil/blob/main/docs/Backward.md/#cxx11_require_call for details.
So if you use C++14, change to REQUIRE_CALL. If you are forced to use C++11, it looks like the RETURN(1) needs to be an argument to REQUIRE_CALL_V
everyone.
I am debugging some problem of type mismatch of a heavily templated class. I would like to know c++ type information during compilation, so I write this:
#pragma message typeinfo(var)
It just do not work.
So I am here asking for some help. I am not sure if it is possible. But I think the compiler must know the type information during compilation.
The preprocessor is not going to help you much itself at compile time. It's job is preprocessing, which happens before compile time.
If the idea is to output type information at compile time then try the following
template <typename...> struct WhichType;
class Something {};
int main() {
WhichType<Something>{};
}
Live example here. When you compile this you should get an error that gives you the type of whatever is inside the templates when trying to instantiate WhichType. This was a neat trick I picked up from Scott Meyers' Effective Modern C++ book. It seems to work perfectly on most mainstream compilers that I have encountered so far.
If you want to get the type information at runtime
#include <iostream>
#include <typeinfo>
using std::cout;
using std::endl;
int main() {
auto integer = int{};
cout << typeid(integer).name() << endl;
}
Note Don't get too comfortable with RTTI (RunTime Type Information) via typeid, C++ also offers several compile time type introspection utilities http://en.cppreference.com/w/cpp/header/type_traits.
I use a type printer helper function, which simply bases on the gcc predefined macro __PRETTY_FUNCTION__. Simply write a templated function which eats everthings and call it from the point where you need to know which type your template expands to. For me it was very helpful to use such a function in case of SFINAE problems and others.
template <typename ... T>
void TemplatePrint(T ... args )
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
auto any = std::tuple_cat( std::tuple<int, double>{}, std::tuple<std::string>{} );
TemplatePrint( any );
}
You did not tag your question to a specific compiler, so you maybe need to search for equivalents on other compilers.
On C++ con some year ago a talk was about:
https://baptiste-wicht.com/posts/2016/02/use-templight-and-templar-to-debug-cpp-templates.html. Maybe this will help to get strange template problems solved.
In a previous question I was trying to figure out at compile time if a particular conversion (of the type to double and back) for a particular fundamental type was safe or not.
Eventually, I figured out the following code:
#include <limits>
#include <vector>
template<class one>
class test {
typedef typename one::value_type v; //My code actually takes std:: containers, not the type directly, so get the type.
typedef std::numeric_limits<v> limits; //Easier to read
static_assert(limits::max()==v(double(limits::max())),"MEANINGFUL ERROR MESSAGE"); //See if the conversion works correctly
};
When it is declared with a "safe" type, like:
test<std::vector<int> > a;
It compiles just fine. But when it is compiled with a type that will not convert correctly, such as:
test<std::vector<unsigned long long> > b;
Rather than failing the assertion as I expected, it fails to compile with the error message (using g++ 4.7.1 and 5.3.0 with --std=c++11):
test2.cpp: In instantiation of ‘class test<std::vector<long long unsigned int> >’:
test2.cpp:11:40: required from here
test2.cpp:8:5: error: non-constant condition for static assertion
static_assert(limits::max()==v(double(limits::max())),"MEANINGFUL ERROR MESSAGE");
I suppose that it is still getting the job done (not compiling when there's a problem, but I still can't figure out why limits::max()==v(double(limits::max())) doesn't count as a constant condition, and I don't really like the fact that it makes the error message less comprehensible. What am I doing wrong?
Thanks!
My crappy solution I just came up with:
#include <limits>
#include <vector>
template<class one>
class test {
typedef typename one::value_type v; //My code actually takes std:: containers, not the type directly, so get the type.
typedef std::numeric_limits<v> limits; //Easier to read
static_assert(double(limits::max())!=double(limits::max())+1),"MEANINGFUL ERROR MESSAGE"); //Once the value is large enough that integers are not exactly representable, x==x+1 for doubles.
};
I'm still hoping I'll find a better solution, though. This feels wrong somehow and I'm not sure it'll work in all cases. At the very least I would need to handle floating point conversions separately.
I expected the following code to work, but I received a compile error:
error C2975: 'n' : invalid template argument for 'foo', expected compile-time constant expression
#include <iostream>
using namespace std;
template<int N>
struct foo
{
foo() { cout << N << endl; }
};
int main()
{
foo< __LINE__ > f;
}
Why does this happen? I though __LINE__ would paste in the line number before template instantiation occurred?
If I wanted to do this should I just introduce a static const int to hold the line number or is there a standard solution?
Works for me in VS 2010 10.0.40219.1 SP1Rel and in Ideone
But MSDN mentions problems which result in C2975, if using __LINE__ in template with compiler-option /ZI: MSDN C2975
Edit: Sorry, I linked the german version, here in english
For what it's worth, this is suppose to be valid code. __LINE__ is suppose to behave as if it were:
#define __LINE__ 0
Of course, replacing 0 with the current line number.
#Bob, you are going to love this one!
I was interested in your question so I tried your code. It compiled in g++ but fails with your error in MSVC10. To investigate, I used Google to find out how to see the preprocessor output: you set "Properties | C++ | Preprocessor | Preprocess to a file" to true. And then I compiled again... AND IT WORKED! Turns out if this option is disabled, the compile fails; if it's enabled, the compile works. I suppose MS doesn't bother to generate LINE entries unless the preprocessor output is being captured. Oy va voy!