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,"");
};
Related
How to specialize a template function for the case that the value of one of its argument is known/unknown during compile time (before actually compile and run the program)?
I can't figure out how yet.
idea 1:
#include <type_traits>
#include <iostream>
int main(void){
int a; //value of a is not known at compile time
bool b = (a == a); //value of b is known at compile time.
std::is_assignable< constexpr bool, bool >::value
}
//g++ magic.cpp -std=c++14
//error: wrong number of template arguments (1, should be 2)
// std::is_assignable< constexpr bool, bool >::value
Idea 2:
#include <type_traits>
#include <iostream>
int main(void){
const int a=1;
int b = (a == a);
std::cout << __builtin_constant_p (a) << std::endl;
std::cout << __builtin_constant_p (b) << std::endl;
}
//prints 0 and 0.
Well, I guess you mean the type of the argument, right? Values don't matter for partial template specializations...
Then: This can't be done.
Parameter types for templates must be known at compile time. How else should the compiler produce the correct code?
Also for partial template specializations, the types must be known at compile time for the same reason.
I'm a bit late to the party, and my partial answer may not be very satisfying, but here goes:
Situations where we can't tell from inspection whether a value is known at compile time:
Non-template input values to constexpr functions
Members of types provided by template arguments
I don't know what to do about problem 1, but for problem 2 we can use SFINAE: looking for a specific member with known name (in the below example it's X), and trying to send it as a template argument, like so:
// like std::void_t, but for value inputs:
template <auto>
using v_to_void_t = void;
//////////////////////////////////////////////////////////////
template <class, class = void>
struct has_constexpr_X
: std::false_type {};
template <class T>
struct has_constexpr_X <T, v_to_void_t<T().X>>
: std::true_type {};
template <class T>
constexpr bool has_constexpr_X_v
= has_constexpr_X<T>::value;
Example uses:
struct HasStaticConstexprX {
static constexpr int X = 2;
};
struct HasStaticConstX {
static const int X; // implied constexpr
};
const int HasStaticConstX::X = 3;
struct HasStaticX {
static int X;
};
int HasStaticX::X = 4;
struct HasConstX {
const int X;
};
int main () {
static_assert(has_constexpr_X_v<HasStaticConstexprX>);
static_assert(has_constexpr_X_v<HasStaticConstX>);
static_assert(! has_constexpr_X_v<HasStaticX>);
static_assert(! has_constexpr_X_v<HasConstX>);
}
Demos:
c++17
c++14
I have a problem when I want to check certain template-parameters for their validity using some helper struct and constepxr functions. As long as there is no reference to the static constexpr member I want to initialize the compiler decides not to evaluate the expression. The code I use is the following:
#include <cstddef>
#include <iostream>
#define CONSTEXPR static constexpr
using namespace std;
template<size_t ... Sizes>
struct _size_check_impl
{
static_assert(sizeof...(Sizes) != 0, "Dimension has to be at least 1");
CONSTEXPR size_t dimension = sizeof...(Sizes);
};
template<size_t ... Sizes>
constexpr size_t check_sizes()
{
return _size_check_impl<Sizes...>::dimension;
}
template<size_t ... Sizes>
struct Test
{
static constexpr size_t Final = check_sizes<Sizes...>();
};
int main()
{
Test<> a; // This shouldn't get through the static assert
Test<1, 2> b; // Passing
Test<2> c; // Passing
// cout << Test<>::Final; // With this it works just fine, bc Final is accessed
return 0;
}
Is there a way I can do this, some proxy dependecy that forces the compiler to evaluate the Final value if constexpr are evaluated? Is there another, clean way to check this property clean and quickly?
The simple answer would probably be to simply add another static_assert:
template<size_t ... Sizes>
struct Test
{
static constexpr size_t Final = check_sizes<Sizes...>();
static_assert(Final > 0, "");
};
This will lead to two separate static assertion failures, though. If that is a problem for you, you could make sure check_sizes, or Final, is used some other way that must necessarily be evaluated at template class instantiation time, without instantiation of any member, for instance:
template<size_t ... Sizes>
struct Test
{
static constexpr decltype(check_sizes<Sizes...>(), size_t()) Final = check_sizes<Sizes...>();
};
Yet another option: if Test<...> is a class that is expected to be constructed normally, you could make sure Final is used from the constructor somehow.
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.
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.
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()'