Static Assert inside struct allowed? - c++

I have several template settings struct, is it ok, to use static asserts in these structs?
template<typename T, int N, (and so on...)>
struct Settings{
static const int n = N;
STATIC_ASSERT(n == 5);
typedef typename T GAGA;
}
Thanks for your responses!

I don't know what your STATIC_ASSERT is but if you write it using c++11 style static_assert then this works fine and seems like a perfectly good use for static assert. (Well, perhaps not checking it's 5 but checking template parameters are suitable for instantating)
template<typename T, int N>
struct Settings {
static const int n = N;
static_assert(n == 5, "Error");
typedef typename T GAGA;
};

You would have to look at the STATIC_ASSERT macro definition to see what is exactly going on. A common implementation of STATIC_ASSERT that can be used there could be:
#define STATIC_ASSERT( x ) \
typedef char static_assert_failed[ (x) ? 1 : -1 ]
Usually there is a bit more trickery to get the line number to be part of the typedef so that more than one STATIC_ASSERT can be used in the same context, but you can see that this is allowed as it will expand to valid code in the struct definition:
template<typename T, int N, (and so on...)>
struct Settings{
static const int n = N;
typedef char static_assert_failed[ (n == 5) ? 1 : -1 ];
typedef typename T GAGA;
}

template<typename T, int N>
struct Settings
{
STATIC_ASSERT(N == 5);
typedef typename T GAGA;
};
I dont see a valid reason to use n.

Related

How to detect C-style multidimensional arrays in templates specialization?

I have the following code:
enum type_kind{unkown=-1,carray, multi_carray};
template<class T>
struct detect_carray{
constexpr static int kind=unkown;
};
template<class T, std::size_t N>
struct detect_carray<T[N]>{
constexpr static int kind=carray;
};
Now, I want to add another specialization for detecting multidimensional arrays in C-style, that is, T[a][b]....
What is the syntax to achieve this? Can I use Variadic templates?
I expect the following behavior:
int main()
{
std::cout<<detect_carray<std::vector<int>>::kind;//-1
std::cout<<detect_carray<int[3]>::kind;//0
std::cout<<detect_carray<double[3][5]>::kind;//1
std::cout<<detect_carray<std::complex<double>[3][5][8][16]>::kind;//1
//Correct out: -1011
}
There's already a trait called std::rank in the standard library so the solution is quite simple:
template <class T>
struct detect_carray {
enum type_kind { unknown = -1, carray, multi_carray };
static constexpr int kind = [] {
switch (std::rank_v<T>) {
case 0: return unknown;
case 1: return carray;
default: return multi_carray;
}
}();
};
Just add a specialization for multidimensional arrays:
template<class T, std::size_t N1, std::size_t N2>
struct detect_carray<T[N1][N2]>{
constexpr static int kind=multi_carray;
};
then
std::cout<<detect_carray<std::vector<int>>::kind;//-1
std::cout<<detect_carray<int[3]>::kind;//0
std::cout<<detect_carray<double[3][5]>::kind;//1
std::cout<<detect_carray<std::complex<double>[3][5][8][16]>::kind;//1
LIVE
BTW: For double[3][5], T will be double (and N1 will be 3 and N2 will be 5). For std::complex<double>[3][5][8][16], T will be std::complex<double> [8][16] (and N1 will be 3 and N2 will be 5).

C++ conditional giving an error

Take a look at this piece of code:
#include <iostream>
using namespace std;
using ld = long double;
template<int i>
struct A {
static_assert(false,"");
constexpr static int value = 3;
};
template<int i>
struct B {
constexpr static int value = i*i*i;
};
template<int i>
struct CheckVal {
constexpr static int value = conditional<i == 1,A,B><3>::value;
};
This is supposed to terminate the compilation if a 1 is passed to CheckVal, but I'm getting the following error on compilation, no matter what is passed to CheckVal:
error: use of class template 'A' requires template arguments
constexpr static ld value = conditional<i == 1,A,B><3>::value;
What is the problem here? How can I fix it?
The only place, where you use A, is inside conditional<>.
A requires a template argument, namely template<int i>.
So, instead of A, you must say A<i> or A<3> or ... same for B.
And finally, you must remove <3> as your compiler will tell you:
template<int i>
struct CheckVal {
constexpr static int value = conditional<i == 1, A<i>, B<i> >::value;
};
However, the compiler (at least g++) will fail with
error: static assertion failed:
static_assert(false,"");
^
First of all your static_assert will always trigger, so not sure what was the purpose of it. If you comment it out, this is what you need to change in CheckVal to make it work:
template<int i>
struct CheckVal
{
constexpr static int value = std::conditional<i == 1, A<3>, B<3>>::type::value;
};
std::conditional will select either A<3> or B<3> depending on condition, then you first need to return the type ::type and only then you can get the ::value member
Demo: https://ideone.com/tozaYr
I'm not really sure what you are trying to achieve but isn't this much simpler construct sufficient?
template<int i>
struct CheckVal {
static_assert(i != 1,"");
};

Const receiving a var, i cant pass it to a template

What I want to do is:
int const bitsPerInt = log2(X);
bitset<bitsPerInt> bits(a random number...);
but I get this error:
'bitsPerInt' cannot appear in a constant expression
error: template argument 1 is invalid
If you really need this to work, make your own log2 that works in compile-time and pass it to bitset's template argument.
constexpr unsigned Log2(unsigned n, unsigned p = 0) {
return (n <= 1) ? p : Log2(n / 2, p + 1);
}
constexpr size_t bitCount = Log2(X);
std::bitset<bitCount> bits;
Live example.
Here's the solution using template meta-programming i.e. without using constexpr:
template<int N,unsigned int P=0>
struct Log2 { enum { value = Log2<N/2,P+1>::value }; };
template <unsigned p>
struct Log2<0, p> { enum { value = p }; };
template <unsigned p>
struct Log2<1, p> { enum { value = p }; };
std::bitset<Log2<4>::value> bits;
Live example.
This version should work in both C++03 and C++11; however, if you've access to C++11, I'd still recommend the constexpr way since it's cleaner (easier to understand).
Template parameter needs to be known(and constant if it is a value and not a type) at compile time. This is how templates work in C++. Templates actually generate real code for each specific version of the generic code.

Runtime function branching on compile-time function?

Consider a compile-time function of the form:
template <unsigned int Value>
constexpr unsigned int function()
{
// Just for the example, but it could be very complicated here
return Value*Value;
}
How to write the runtime equivalent that will call the right compile-time version using template metaprogramming, knowing that the value will always be in the [From, To[ interval:
template <unsigned int From, unsigned int To, /* Something here */>
constexpr unsigned int function(const unsigned int value)
{
// Something here
}
The branching to the right version should be as fast as possible.
For example function<0, 32>(6) (runtime version) should call function<6>() (compile-time version).
EDIT: Explanation:
Why do I want to do this? This function (real use case) need to be as fast as possible (supercomputing issues). By providing the parameter at compile-time, I can generate very efficient code. If I simply move the value from the template parameter to a function parameter, the code is between 10 and 100 times slower. But in fact, this parameter does not have a very wide range of possible values (like between 0 and 32): so it would be far more efficient to branch at runtime on the right compile-time version.
The easiest way is to set up a recursive cascading if/recurse chain.
#define RETURNS(X) -> decltype(X) { return (X); }
template<unsigned From, unsigned To, typename Target>
struct CallIf {
constexpr auto operator()( unsigned N )
RETURNS( (N==From)?Target::template func<From>():CallIf<From+1, To, Target>()( N ) );
};
template<unsigned From, typename Target>
struct CallIf<From, From+1, Target> {
constexpr auto operator()( unsigned N )
RETURNS( Target::template func<From>() );
};
struct Func {
template<unsigned V>
constexpr unsigned func() const {
return function<V>();
}
};
or something like that, and rely on the compiler collapsing that chain of ifs down to one. (if you know the return type, you can do away with that annoying RETURNS macro, or if you have C++1y features you can do the same).
Now, you might want to compare this to a version that does a binary search on value in that range, using a similar recursive call case. Similarly, you could do it by checking and setting bits in a compile time value.
template<unsigned From, unsigned To, typename Target>
struct CallIf {
enum { Mid = From + (To-From)/2 }; // avoid overflow risk
constexpr auto operator()( unsigned N )
RETURNS( (N>=Mid)?CallIf<Mid, To, Target>()(N):CallIf<From,Mid,Target>()(N) );
};
with the same specialization for the 1-width case.
Another approach would be to set up a static array of invocations of function<V> and then do an array dereference at run time:
template<unsigned...> struct indexes {};
template<unsigned Min, unsigned Max, unsigned... Is> struct make_indexes:make_indexes<Min, Max-1, Max-1, Is...> {};
template<unsigned Min, unsigned... Is> struct make_indexes<Min, Min, Is...>:indexes<Is...> {};
template<unsigned From, unsigned To, typename Target>
struct CallIf {
template<unsigned... Is>
unsigned Invoke( indexes<Is...>, unsigned N ) const {
typedef unsigned(*target)();
static target ts[] = { &(function<Is>)... };
return ts[N-From]();
};
unsigned operator()( unsigned N ) const {
return Invoke( make_indexes<From, To>(), N );
}
};
although I'm not sure how to make the above constexpr easily in C++11 at least, and I skipped out on doing return-type deduction.
None of the above are tested or compiled, so most likely will require some repair. But the core concept will work. The specialization might need some work: doing <From, From+1 to terminate is something I haven't done in practice: if that causes issues, you can do <From, Width based helper, and specialize on Width=1.
I personally call this technique (embodied in the CallIf type above) the "magic switch", where we take a run time valid and "magically" make it a compile time value. I only mention this because you can probably find me talking about it on stack overflow by googling Yakk and "magic switch" (and site:stackoverflow.com) for other variations, some of which have been compiled and have live examples attached.
Finally, while the last version (the manual jump table) may be fastest, if you are calling it so often that the speed of this invocation is key, you might want to think about wrapping not just the call site, but the algorithm surrounding it in a magic switch: do the dispatching earlier. If, however, you only get the index at the last moment, and you are ok with a non-constexpr call, it should work. Note that static arrays will be created for each Function and To and From used.
You may create an (constexpr) array of results, something like :
#if 1 // Not in C++11
template <std::size_t ...> struct index_sequence {};
template <std::size_t I, std::size_t ...Is>
struct make_index_sequence : make_index_sequence < I - 1, I - 1, Is... > {};
template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
#endif
template <unsigned int Value>
constexpr unsigned int function()
{
// Just for the example, but it could be very complicated here
return Value * Value;
}
namespace detail
{
template <std::size_t From, std::size_t...Is>
struct result_array
{
static constexpr std::array<unsigned int, sizeof...(Is)> values = {{::function<From + Is>()...}};
};
template <std::size_t From, std::size_t...Is>
constexpr std::array<unsigned int, sizeof...(Is)> result_array<From, Is...>::values;
template <std::size_t From, std::size_t...Is>
constexpr unsigned int function(unsigned int value, index_sequence<Is...>)
{
return result_array<From, Is...>::values[value - From];
}
} // namespace detail
template <unsigned int From, unsigned int To>
constexpr unsigned int function(const unsigned int value)
{
static_assert(From < To, "Invalid template parameters");
return detail::function<From>(value, make_index_sequence<std::size_t(To + 1 - From)>());
}

C++ metaprogramming - generating errors in code

Is there a way that I can create a function that takes an int template parameter, and have that function give a compile time error if the value passed to the function is less than 10?
The following code does not work, but it shows what I want to accomplish:
template <int number1>
void reportErrorIfLessThan10()
{
#if(number1 < 10)
#error the number is less than 10
#endif
}
int maint(int argc, char**argv)
{
reportErrorIfLessThan10<5>();//report an error!
reportErrorIfLessThan10<12>();//ok
return 0;
}
If you don't want Boost C++ Libraries magic and want bare bones...
template<bool> class static_check
{
};
template<> class static_check<false>
{
private: static_check();
};
#define StaticAssert(test) static_check<(test) != 0>()
Then use StaticAssert. It's a #define for me because I have code that needs to run in a lot of environments where C++ doesn't work right for templates and I need to just back it off to a runtime assert. :(
Also, not the best error messages.
If for some reason you can't use Boost, this example is trivially written like this:
template <int number1>
void reportErrorIfLessThan10()
{
typedef char number1_gt_10[number1 > 10 ? 1 : -1];
}
int maint(int argc, char**argv)
{
reportErrorIfLessThan10<5>();//report an error!
reportErrorIfLessThan10<12>();//ok
return 0;
}
Or more generic
#define static_assert(test, message) typedef char static_assert_at_ ## __LINE__[(test) ? 1 : -1];
I'm not concatenating the error message itself, because I feel that static_assert(true, "some message"); is more readable than say static_assert(true, some_message);. However, this does limit the use case to only one assert per line.
template <int number1>
typename boost::enable_if_c< (number1 >= 10) >::type
reportErrorIfLessThan10() {
// ...
}
The above enable_if, without the _c because we have a plain bool, looks like this:
template<bool C, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> { };
Boost's enable_if takes not a plain bool, so they have another version which has a _c appended, that takes plain bools. You won't be able to call it for number1 < 10. SFINAE will exclude that template as possible candidates, because enable_if will not expose a type ::type if the condition evaluates to false. If you want, for some reason, test it in the function, then if you have the C++1x feature available, you can use static_assert:
template <int number1>
void reportErrorIfLessThan10() {
static_assert(number >= 10, "number must be >= 10");
}
If not, you can use BOOST_STATIC_ASSERT:
template <int number1>
void reportErrorIfLessThan10() {
BOOST_STATIC_ASSERT(number >= 10);
}
The only way to display a descriptive message is using static_assert, though. You can more or less simulate that, using types having names that describe the error condition:
namespace detail {
/* chooses type A if cond == true, chooses type B if cond == false */
template <bool cond, typename A, typename B>
struct Condition {
typedef A type;
};
template <typename A, typename B>
struct Condition<false, A, B> {
typedef B type;
};
struct number1_greater_than_10;
}
template <int number1>
void reportErrorIfLessThan10() {
// number1 must be greater than 10
sizeof( typename detail::Condition< (number1 >= 10),
char,
detail::number1_greater_than_10
>::type );
}
It prints this here:
error: invalid application of 'sizeof' to incomplete type 'detail::number1_greater_than_10'
But I think the very first approach, using enable_if will do it. You will get an error message about an undeclared reportErrorIfLessThan10.
litb and Joe have already given the answers used in practice. Just to illustrate how this can be done manually by specializing for the number in question (rather than a general boolean condition):
template <int N>
struct helper : helper<N - 1> { };
template <>
struct helper<10> { typedef void type; };
template <>
struct helper<0> { }; // Notice: missing typedef.
template <int N>
typename helper<N>::type error_if_less_than_10() {
}
int main() {
error_if_less_than_10<10>();
error_if_less_than_10<9>();
}
Functions cannot be inherited but classes (and structs) can. Therefore, this code also uses a struct that automatically and dynamically generates cases for all N except 10 and 0, which are the hard-coded recursion begins.
By the way, the above code actually gives quite nice error messages:
x.cpp:16: error: no matching function for call to 'error_if_less_than_10()'