Skip to content

Commit 5ba5a0f

Browse files
author
Oğuzhan Katlı
committed
- added example for static assertation for pre c++11 compilers.
1 parent b0af68b commit 5ba5a0f

File tree

4 files changed

+162
-3
lines changed

4 files changed

+162
-3
lines changed

AdvancedCppICTerra2018.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@
182182
<ClInclude Include="src/7-Exceptions/exception_usage.hpp" />
183183
<ClInclude Include="src/8-CustomComparators/custom_comparator.hpp" />
184184
<ClInclude Include="src/9-AsyncFuture/async_usage.hpp" />
185+
<ClInclude Include="src\6-Templates\template_static_assert.hpp" />
185186
</ItemGroup>
186187
<ItemGroup>
187188
<ClCompile Include="main.cpp" />

AdvancedCppICTerra2018.vcxproj.filters

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@
7373
<ClInclude Include="src/7-Exceptions/exception_usage.hpp">
7474
<Filter>7- Exceptions</Filter>
7575
</ClInclude>
76-
<ClInclude Include="src/8-CustomComparators/custom_comparator.hpp">
77-
<Filter>8- Custom Comparators</Filter>
78-
</ClInclude>
7976
<ClInclude Include="src/9-AsyncFuture/async_usage.hpp">
8077
<Filter>9- Async &amp; Future</Filter>
8178
</ClInclude>
@@ -88,6 +85,12 @@
8885
<ClInclude Include="src\6-Templates\template_policies.hpp">
8986
<Filter>6- Templates</Filter>
9087
</ClInclude>
88+
<ClInclude Include="src/8-CustomComparators/custom_comparator.hpp">
89+
<Filter>8- Custom Comparators</Filter>
90+
</ClInclude>
91+
<ClInclude Include="src\6-Templates\template_static_assert.hpp">
92+
<Filter>6- Templates</Filter>
93+
</ClInclude>
9194
</ItemGroup>
9295
<ItemGroup>
9396
<Filter Include="2- Inheritance">

main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "src/6-Templates/template_decltype.hpp"
3434
#include "src/6-Templates/template_container.hpp"
3535
#include "src/6-Templates/template_policies.hpp"
36+
#include "src/6-Templates/template_static_assert.hpp"
3637

3738
// 7- exceptions
3839
#include "src/7-Exceptions/exception_usage.hpp"
@@ -78,6 +79,7 @@ int main(int argc, char *argv[]) {
7879
.Add<MixinTemplateExample>()
7980
.Add<TemplatePolicies>()
8081
.Add<TemplateDecltypeUsage>()
82+
.Add<TemplateStaticAssert>()
8183
// 7- exceptions
8284
.Add<ExceptionUsage>()
8385
// 8- custom comparators
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#pragma once
2+
#include <playground_organizer.hpp>
3+
#include <iostream>
4+
#include "src/0-Types/number.hpp"
5+
6+
using namespace std;
7+
8+
namespace staticassert {
9+
10+
namespace definition {
11+
#pragma warning( push )
12+
#pragma warning( disable : 4101) // disable compiler warning for unused variable unnamed
13+
/*
14+
The simplest solution to compile-time assertions (Van Horn 1997), and one that works in C as well as in
15+
C++, relies on the fact that a zero-length array is illegal.
16+
*/
17+
#define STATIC_CHECK(expr) { char unnamed[(expr) ? 1 : 0]; }
18+
19+
template <class To, class From>
20+
To safe_reinterpret_cast(From from)
21+
{
22+
// if size of 'From' type are larger 'To', the compiler complains that you are trying to
23+
// create an array of length zero.
24+
STATIC_CHECK(sizeof(From) <= sizeof(To));
25+
return reinterpret_cast<To>(from);
26+
}
27+
28+
void willsuccess() {
29+
alignas(int) char stack_buffer[sizeof(int)];
30+
int *val = new(stack_buffer) int(3);
31+
char *bytes = safe_reinterpret_cast<char*>(val);
32+
printf("\ninteger bytes : %d %d %d %d\n", bytes[0], bytes[1], bytes[2], bytes[3]);
33+
}
34+
35+
/*
36+
The problem with this approach is that the error message you receive is not terribly informative.
37+
"Cannot create array of size zero" does not suggest "Type char is too narrow to hold a pointer."
38+
It is very hard to provide customized error messages portably. Error messages have no rules that
39+
they must obey; it's all up to the compiler. For instance, if the error refers to an undefined variable,
40+
the name of that variable does not necessarily appear in the error message
41+
*/
42+
void willfail() {
43+
alignas(double) char stack_buffer[sizeof(double)];
44+
double* somePointer = new (stack_buffer) double(3.14);
45+
// uncommenting below line will fail compile by giving static assertation error! "error C2466: cannot allocate an array of constant size 0"
46+
// char c = safe_reinterpret_cast<char>(somePointer);
47+
}
48+
#pragma warning( pop )
49+
} // namespace definition
50+
51+
namespace usingtemplates {
52+
53+
template<bool> struct CompileTimeError;
54+
// no implementation for false case to create compile time assertation
55+
template<> struct CompileTimeError<true> {};
56+
57+
#ifdef STATIC_CHECK
58+
#undef STATIC_CHECK
59+
#endif
60+
// redefine static check macro
61+
#define STATIC_CHECK(expr) (CompileTimeError<(expr) != 0>())
62+
63+
template <class To, class From>
64+
To safe_reinterpret_cast(From from)
65+
{
66+
STATIC_CHECK(sizeof(From) <= sizeof(To));
67+
return reinterpret_cast<To>(from);
68+
}
69+
/*
70+
CompileTimeError is a template taking a nontype parameter (a Boolean constant). Compile-
71+
TimeError is defined only for the true value of the Boolean constant. If you try to instantiate
72+
CompileTimeError<false>, the compiler utters a message such as "Undefined specialization
73+
CompileTimeError<false>." This message is a slightly better hint that the error is intentional and not
74+
a compiler or a program bug.
75+
*/
76+
void willfail() {
77+
alignas(double) char stack_buffer[sizeof(double)];
78+
double* somePointer = new (stack_buffer) double(3.14);
79+
// uncommenting below line will fail compile by giving static assertation error! "error C2466: cannot allocate an array of constant size 0"
80+
//char c = safe_reinterpret_cast<char>(somePointer);
81+
}
82+
83+
} // namespace usingtemplates
84+
85+
namespace witherrormsg {
86+
87+
// added ctor with any type
88+
template<bool> struct CompileTimeChecker {
89+
CompileTimeChecker(...) { }
90+
};
91+
// in here we specialized for false type and not implemented ctor for false
92+
template<> struct CompileTimeChecker<false> {};
93+
94+
#ifdef STATIC_CHECK
95+
#undef STATIC_CHECK
96+
#endif
97+
// redefine static check macro
98+
#define STATIC_CHECK(expr, msg) \
99+
{ \
100+
class ERROR_##msg {}; \
101+
(void)sizeof(CompileTimeChecker<(expr) != 0>((ERROR_##msg()))); \
102+
}
103+
104+
/*
105+
After macro preprocessing, the code of safe_reinterpret_cast expands to the following:
106+
template <class To, class From>
107+
To safe_reinterpret_cast(From from)
108+
{
109+
{
110+
class ERROR_Destination_Type_Too_Narrow {};
111+
(void)sizeof(
112+
CompileTimeChecker<(sizeof(From) <= sizeof(To))>(
113+
ERROR_Destination_Type_Too_Narrow()));
114+
}
115+
return reinterpret_cast<To>(from);
116+
}
117+
*/
118+
template <class To, class From>
119+
To safe_reinterpret_cast(From from)
120+
{
121+
STATIC_CHECK(sizeof(From) <= sizeof(To), Destination_Type_Too_Narrow);
122+
return reinterpret_cast<To>(from);
123+
}
124+
125+
/*
126+
Now here's the trick. The CompileTimeChecker<true> specialization has a constructor that accepts
127+
anything; it's an ellipsis function. This means that if the compile-time expression checked evaluates to
128+
true, the resulting program is valid. If the comparison between sizes evaluates to false, a compile-time
129+
error occurs: The compiler cannot find a conversion from an
130+
ERROR_Destination_Type_Too_Narrow to a CompileTimeChecker<false>. And the nicest
131+
thing of all is that a decent compiler outputs an error message such as "Error: Cannot convert
132+
ERROR_Destination_Type_Too_Narrow to CompileTimeChecker <false>."
133+
*/
134+
void willfail() {
135+
alignas(double) char stack_buffer[sizeof(double)];
136+
double* somePointer = new (stack_buffer) double(3.14);
137+
// uncommenting below line will fail compile by giving static assertation error! "error C2466: cannot allocate an array of constant size 0"
138+
//char c = safe_reinterpret_cast<char>(somePointer);
139+
}
140+
141+
} // namespace usingtemplates
142+
143+
} // namespace staticassert
144+
145+
CREATE_ELEMENT_WITH_CODE(TemplateStaticAssert) {
146+
namespace sa = staticassert;
147+
148+
sa::definition::willsuccess();
149+
sa::definition::willfail();
150+
151+
sa::usingtemplates::willfail();
152+
sa::witherrormsg::willfail();
153+
}

0 commit comments

Comments
 (0)