Using Extended Embedded Cpp. How can I make this result in a compilation error in a release build:
Param okParam("Yeah!"); // this line should be ok
Param nOkParam("REEEEEEEEEEE"); // too big array, not ok. compiler error.
where:
int const c_max = 10;
template<int N>
struct Param
{
char value[c_max];
Param(char const (&p_value)[N])
{
memcpy(value, p_value, sizeof(p_value));
}
};
I don't think you can template the constructor, so the entire struct needs to be templated, right?
I want this to provide a clean compiler error so that the person using this will notice it immediately.
Our version of extended embedded C++ doesn't provide any stl containers, I'm not sure if it's even possible.
I'm looking for some way to make the template result in a good compilation error. Sadly I can't use boost either, since the platform would not support it.
You have basically two solutions: SFINAE (C++98) or static_assert (C++11):
SFINAE
You can provide a constructor for Param only for char arrays less than a given size long. In C++98 this looks a bit ugly, but it works:
#include <cstddef>
template<bool b>
struct enable_if {};
template<>
struct enable_if<true>
{
typedef int type;
};
template<std::size_t MAXSIZE>
struct Param
{
template<std::size_t SIZE>
explicit Param(
char const (&input) [SIZE],
std::size_t = sizeof(typename enable_if<SIZE < MAXSIZE>::type) // SFINAE at work
) { (void) input; }
};
int main()
{
// "hello": char const[6], 6 < 7, OK
Param<7> p1("hello");
// "hello world": char const[12], 12 >= 7, KO
Param<7> p2("hello world"); // ugly error here
}
Live demo
Assert (C++11 only)
Inside the constructor of Param, you can check if the supplied char array is too big and pop a readable error at compilation-time:
#include <cstddef>
#include <type_traits>
template<std::size_t MAXSIZE>
struct Param
{
template<std::size_t SIZE>
explicit Param(char const (&input) [SIZE])
{ static_assert(sizeof(input) < MAXSIZE, "input is too big."); }
};
int main()
{
// "hello": char const[6], 6 < 7, OK
Param<7> p1("hello");
// "hello world": char const[12], 12 >= 7, KO
Param<7> p2("hello world"); // "error: static assertion failed: input is too big."
}
Live demo
Probably the simplest way is to add a static_assert, using one of the old C techniques for compile-time checks if your implementation doesn't have static_assert yet:
#include <cstring>
#if __cplusplus < 201103L
#define static_assert(expr, message) \
int static_assert_(int (&static_assert_failed)[(expr)?1:-1])
#endif
template<int N>
struct Param
{
static const int c_max = 10;
static_assert(N < c_max, "Param string too long");
char value[c_max];
Param(char const (&p_value)[N])
{
std::memcpy(value, p_value, sizeof p_value);
}
};
int main()
{
Param okParam("Yeah!"); // this line should be ok
Param nOkParam("REEEEEEEEEEE"); // too big array, not ok. compiler error.
}
Related
With the following code:
#include <algorithm>
constexpr int DATA_SIZE = 5;
constexpr int A_ARRAY_ALLOWED_SIZE = 5;
constexpr int A_ARRAY_SIZE = std::min(A_ARRAY_ALLOWED_SIZE, DATA_SIZE);
constexpr int B_ARRAY_SIZE = DATA_SIZE - A_ARRAY_ALLOWED_SIZE;
class A {
int a[A_ARRAY_SIZE];
};
class B {
int b[B_ARRAY_SIZE];
};
int main()
{
A a;
if constexpr (B_ARRAY_SIZE)
{
B b;
}
return 0;
}
I'm getting compiler error (with -pedantic flag) which complains that zero-size array is not allowed. In my example the object with the zero size array is never created but looks like it is still an issue.
I was trying to workaround it with usage of std::conditional but even then I ended up with an additional function like:
constexpr int Get_B_ARRAY_SIZE()
{
if (B_ARRAY_SIZE)
return B_ARRAY_SIZE;
return 1; // workaround for zero-size array
}
What is a proper way of handling such an issue?
EDIT:
I'm aware that all of if branches should contain valid code. I'm also aware that zero-size arrays are not allowed. My question is how to refactor this code to get similar behawior like when compiling without -pedantic flag. I suspect that I can use template meta programming to achieve this purpose but I'm not sure how to do it.
If you need equivalent of std::conditional, but for values, rather than types, you can do it like this:
#include <iostream>
#include <type_traits>
template<size_t N>
struct safe_array_size : std::integral_constant<size_t, N> {};
template<>
struct safe_array_size<0> : std::integral_constant<size_t, 1> {};
int main()
{
char a[safe_array_size<0>::value];
char b[safe_array_size<1>::value];
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(b) << std::endl;
}
Or using std::conditional:
#include <iostream>
#include <type_traits>
template<size_t N>
constexpr size_t safe_array_size = std::conditional_t<N==0, std::integral_constant<size_t, 1>, std::integral_constant<size_t, N>>::value;
int main()
{
char a[safe_array_size<0>];
char b[safe_array_size<1>];
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(b) << std::endl;
}
if constexpr (at least, how you are using it) cannot directly work around this error because it is the class definition that is ill-formed. Whether or not you instantiate the class is irrelevant. You can fix this by ensuring that the array size is never zero with std::max:
#include <algorithm>
constexpr int DATA_SIZE = 5;
constexpr int A_ARRAY_ALLOWED_SIZE = 5;
constexpr int A_ARRAY_SIZE = std::min(A_ARRAY_ALLOWED_SIZE, DATA_SIZE);
constexpr int B_ARRAY_SIZE = DATA_SIZE - A_ARRAY_ALLOWED_SIZE;
class A {
int a[A_ARRAY_SIZE];
};
class B {
int b[std::max(B_ARRAY_SIZE, 1)];
};
int main()
{
A a;
if constexpr (B_ARRAY_SIZE)
{
B b;
}
return 0;
}
Note that std::max is constexpr as of C++14. You could implement your own max function if you are on C++11.
If you need to ensure that the class is never actually instantiated unless the array size is non-zero, the if constexpr check in the above code will handle that.
Say I get an int from a lambda function ran at initialization of a class object. Is it possible to use that int to define the size of a std::array? Something like the following code.
#include <array>
#include <vector>
#include <iostream>
class Test1 {
public:
Test1( std::vector<int> vec1 ) :
nvars([&vec1]() -> int { return vec1.size()+1; }())
{
};
const int nvars;
// ******This isn't allowed!!!!!!!!!
const std::array<int,nvars> arr;
};
int main() {
std::vector<int> vec{1,2,3,4};
Test1 test1(vec);
std::cout << "nvars: " << test1.nvars << std::endl;
return 0;
}
I am a C++ beginner so any other advice will be welcome.
No. The size of the array is part of its type. You cannot let it be determined at runtime.
You can have it be determined at compile time, if you do pass a std::array to the constructor. Since C++17 there is CTAD (class template argument deduction) which lets you write:
#include <array>
template <size_t N>
class Test1 {
public:
Test1( std::array<int,N> vec1 ) :
arr(vec1)
{
};
const std::array<int,N> arr;
};
int main() {
std::array vec{1,2,3,4};
Test1 test1(vec);
}
Live Demo
test1 is of type Test1<4>. Note that Test1<4> is a distinct different type than eg Test<5> or Test<24>. If you want one type to have a member array of different size, make it a std::vector.
Due to specific IO process on ibm i there's requirement of using display file fields IO.
As follows we need compile time structures for display file values.
After looking at constexpr I've decided to try some cpp + templates solution from here.
The final code for my case looks like this:
MYSRC/MYMOD.CPP
#include "MYSRC/MODINCH"
template <int N>
constexpr_string<N> make_constexpr_string(const char(&a)[N]) {
// Provide a function template to deduce N ^ right here
return constexpr_string<N>(a);
// ^ Forward the parameter to the class template.
};
int main(int argc, char** argv)
{
return 0;
}
MYSRC/MODINCH.H
#include <algorithm>
#define __IBMCPP_TR1__ 1
#include <QSYSINC/STD(array)>
using std::size_t;
template <size_t N> // N is the capacity of my string.
class constexpr_string {
private:
//std::tr1::array<char, N> data_; // Reserve N chars to store anything.
char data_[N];
std::size_t size_; // The actual size of the string.
public:
constexpr constexpr_string(const char(&a)[N]): data_{}, size_(N - 1)
{
for (std::size_t i = 0; i < N; ++i) {
data_[i] = a[i];
}
}
constexpr iterator begin() { return data_; } // Points at the beggining of the storage.
constexpr iterator end() { return data_ + size_; } // Points at the end of the stored string.
};
The code above compiles with
CRTCPPMOD MODULE(QTEMP/MYMOD) SRCFILE(MYLIB/MYSRC) SRCMBR(MYMOD)
OPTIMIZE(40) DBGVIEW(*ALL) LANGLVL(*EXTENDED0X)
for both char data_[N]; and std::tr1::array<char, N> data_;
However, when I try to populate instance of constexpr_string like this:
#include "MYSRC/MODINCH"
template <int N>
constexpr_string<N> make_constexpr_string(const char(&a)[N]) {
// Provide a function template to deduce N ^ right here
return constexpr_string<N>(a);
// ^ Forward the parameter to the class template.
};
int main(int argc, char** argv)
{
auto test1 = make_constexpr_string("blabla");
constexpr_string<7> test("blabla");
return 0;
}
error instantly fails compilation with this message
CZP0063(30) The text "constexpr_string" is unexpected. right at the ctor line. For me this looks like compiler can not determine the constexpr keyword in this situation, but why?
Did I messed somewhere in code or this usage just currently unsupported?
Here is the supported features of ibm compiler and the IBM XLC++ supports constexpr as far, as I can deduct from given table.
Given this is tagged as ibm-midrange, I'm not sure the feature set of IBM XLC++ is the proper reference to use. I think you want to be using this instead. In particular if you want to use C++0x features (which are not yet fully supported), you need to compile using LANGLVL(*EXTENDED0X).
For further information, this link shows information on support for ILE C++0x language extensions.
I can't verify this on the ibm-midrange system because I don't have access to the CPP compiler there but I think I've found your issue:
#include "MYSRC/MODINCH"
template <int N>
constexpr_string<N> make_constexpr_string; // <------ You are missing this semicolon
...
int main(int argc, char** argv)
{
auto test1 = make_constexpr_string("blabla");
constexpr_string<7> test("blabla");
return 0;
}
Is there a way (trait or so) to detect, if struct/class has some padding?
I don't need cross-platform or standardized solution, I need it for MSVC2013.
I can check it like
namespace A
{
struct Foo
{
int a;
bool b;
};
}
#pragma pack(push, 1)
namespace B
{
struct Foo
{
int a;
bool b;
};
}
#pragma pack(pop)
static const bool has_padding = sizeof(A::Foo) != sizeof(B::Foo);
But C++ doesn't allow (as far as I know) generate this non-invasive (without touching existing structs)
Ideally I would like to get working something like this
template <typename T>
struct has_padding_impl
{
typedef __declspec(align(1)) struct T AllignedT;
};
template <typename T>
struct has_padding : typename std::conditional<sizeof(typename has_padding_impl<T>::AllignedT) == sizeof(T),
std::false_type,
std::true_type>::type{};
EDIT - Why do I need this?
I'am working with existing serialization system, which store some struct just taking void* to them (inside generic function) and store sizeof(T) number of bytes... Such binary file is not portable on platforms we are targeting, since different compilers are used, so there is no guarantee how is padding inserted. If I could statically detect all T which are structs with padding, I can force user to manually insert padding (some control padding e.g. not just random garbage) so there is no "random" padding. Another adventage is, when I diff two save files of same scenerio, they will look the same.
edit 2
the more I think about it, the more I realize I need cross-platform solution. We mainly develop on msvc2013 but our application is at final builded in msvc2012 and clang. But if I detected and get rid of all compiler-generated padding in msvc2013, there is no guarantee that other compiler doesn't insert padding... (so msvc2013 detection is not enough)
Do you need this information during run time?
Because if you want to know it in build time I believe you can use static_assert to get this information.
struct foo
{
uint64_t x;
uint8_t y;
};
#define EXPECTED_FOO_SIZE (sizeof(uint64_t) + sizeof(uint8_t))
static_assert(sizeof(foo) == EXPECTED_FOO_SIZE, "Using padding!");
If you need it during run time, you can try something like:
static const bool has_padding = (sizeof(foo) != EXPECTED_FOO_SIZE);
Also check this link from earlier post, maybe it will help.
Try out this macro :
#define TO_STR(str) #str
#define DECL_STRUCT_TEST_ALIGNED(structName, test_alignment, body) \
_Pragma(TO_STR(pack(push,test_alignment)))\
struct test_##structName \
body ; \
_Pragma(TO_STR(pack(pop))) \
struct structName \
body; \
static const bool has_padding_##structName = sizeof(test_##structName)!=sizeof(structName);
DECL_STRUCT_TEST_ALIGNED(bar, 1,
{
int a;
bool b;
}
)
DECL_STRUCT_TEST_ALIGNED(foo,1,
{
int a;
int b;
})
And now, at runtime you can test :
if (has_padding_foo)
{
printf("foo has padding\n");
} else {
printf("foo doesn't have padding\n");
}
if (has_padding_bar)
{
printf("bar has padding\n");
} else {
printf("bar has no padding\n");
}
And ofc, you can use static_assert if you want to get error at compile time.
May be you should try something like this:
#include <iostream>
using namespace std;
struct A
{
int a;
bool b;
};
int main(int argc, char *argv[])
{
A foo;
cout << "sizeof struct = " << sizeof(A) << endl;
cout << "sizeof items = " << sizeof(foo.a) + sizeof(foo.b) << endl;
return 0;
}
I got:
sizeof struct = 8
sizeof items = 5
I am on Ubuntu 14.04.
Can I use assert to enforce type definitions. Suppose there is a variable, double d, how can you use assert to assert that d is a double? If assert is not applicable (which I am betting isn't), is there another option? I am specifically looking to test for implicit type casting during debugging, while benefiting from the functionality of assert and #define NDEBUG.
P.S
Obviously I would want to use this for any type definition, just using double as an example here. The solution should be cross platform compatible and be compatible with C++03.
I like to add error checking to my class setters. For example, suppose there is a class, MyClass, with a private member variable, x:
void MyClass::setX(double input)
{
// assert x is double
x = input;
}
It's really a compile time check, so you should use static asserts for this.
Here is an example using boost's static asserts and type traits.
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
template<typename T>
void some_func() {
BOOST_STATIC_ASSERT( (boost::is_same<double, T>::value) );
}
TEST(type_check) {
some_func<double>();
}
I assume you mean in terms of a template anyway.
You can use the == operator defined in the type_info class to test for a specific type definition.
#include <assert.h>
#include <iostream>
#include <typeinfo>
int main ()
{
double a = 0;
std::cout << typeid(a).name() << std::endl;
assert(typeid(a)==typeid(double));
assert(typeid(a)==typeid(int)); // FAIL
}
Or borrowing from another SO answer using templates and try/catch:
#include <assert.h>
#include <iostream>
#include <typeinfo>
template <typename X, typename A>
inline void Assert(A assertion)
{
if( !assertion ) throw X();
}
#ifdef NDEBUG
const bool CHECK_ASSERT = false;
#else
const bool CHECK_ASSERT = true;
#endif
struct Wrong { };
int main ()
{
double a = 0;
std::cout << typeid(a).name() << std::endl;
assert(typeid(a)==typeid(double));
Assert<Wrong>(!CHECK_ASSERT || typeid(a)==typeid(double));
try
{
//assert(typeid(a)==typeid(int)); // FAIL and Abort()
Assert<Wrong>(!CHECK_ASSERT || typeid(a)==typeid(int)); // FALL
}
catch (Wrong)
{
std::cerr <<"Exception, not an int" <<std::endl;
}
}
You should be able to compare using std::is_same and using decltype. You can even use std::static_assert to move the check to compile time. I've seen it happen in libc++ :)
Note these are C++11 features, so you'll need to have a compiler that supports decltype
Given the current definition of the code, a way to check at compile time whether both are of the same type is:
template< typename T, typename U >
void assert_same_type( T const&, U const& )
{
int error[ sizeof( T ) ? -1 : -2 ]; // error array of negative size, dependent on T otherwise some implementations may cause an early error message even when they shouldn't
}
template< typename T >
void assert_same_type( T&, T& ){}
void MyClass::setX(double input)
{
assert_same_type( x, input ); // If the fallback case is instantiated then a compile time error will arise of trying to declare an array of negative size.
x = input;
}
You can create a template function, then overload the argument type for double like this:
#include <cassert>
template<class T>
bool is_double(T) { return false; }
bool is_double(double) { return true; }
int main() {
int i = 1;
double d = 3.14;
assert( is_double(d) );
assert( is_double(i) ); // fails
}
That would give a run-time error. You can generate a compile time error by simply defining a function that takes a double reference:
void is_double(double&) { }
void MyClass::setX(double input)
{
is_double(x); // assert x is double
x = input;
}