I'd like to determine if a string contains a particular character at compile time. I thought I would use std::string_view as it has constexpr methods to do what I want. This is the code:
#include <iostream>
#include <string_view>
using namespace std::literals;
template<std::size_t N>
constexpr bool ContainsAsterisk(const char(&formatString)[N])
{
constexpr std::string_view fmtString{ formatString, N - 1 }; // error C2131: expression did not evaluate to a constant
constexpr bool containsAsterisk = fmtString.find('*') != fmtString.npos;
return containsAsterisk;
}
int main()
{
if (ContainsAsterisk("sdf"))
{
std::cout << "sdf no\n";
}
if (ContainsAsterisk("er*r"))
{
std::cout << "er*r yes\n";
}
std::cout << "done\n";
}
This doesn't compile because of these errors
ConsoleApplication.cpp(9,41): error C2131: expression did not evaluate to a constant
ConsoleApplication.cpp(9,43): message : failure was caused by a read of a variable outside its lifetime
ConsoleApplication.cpp(9,43): message : see usage of 'formatString'
ConsoleApplication.cpp(17): message : see reference to function template instantiation 'bool ContainsAsterisk<4>(const char (&)[4])' being compiled
ConsoleApplication.cpp(10,37): error C2131: expression did not evaluate to a constant
ConsoleApplication.cpp(9,43): message : failure was caused by a read of a variable outside its lifetime
ConsoleApplication.cpp(9,43): message : see usage of 'formatString'
I've done quite a bit of googling, and can't understand what this error is telling me! I don't understand how the variable is being read outside it's lifetime, it's a literal (isn't it?) that I thought would be available at compile time.
Any tips explaining the error and how to fix would be appreciated. Thanks.
You are overcomplicating things. std::string_view can be constructed by const char*:
constexpr bool ContainsAsterisk(std::string_view view) {
// constexpr bool b = view.find('*') != view.npos; // ERROR
return view.find('*') != view.npos;
}
int main() {
constexpr bool b = ContainsAsterisk("123123*"); // OK
}
Why am I getting the error?
According to cppreference, a function can be constexpr if:
there exists at least one set of argument values such that an
invocation of the function could be an evaluated subexpression of a
core constant expression [...]
This means that it's not necessary for a constexpr function to always return a constexpr value, neither is it expected to always receive a constexpr argument. It only makes sure that for some specific set of arguments (a constexpr const char* in thie case), it will give a constexpr return value.
Therefore, a definition that assumes the argument is always constexpr (see ERROR line above) is invalid.
Your code can simply be written as:
template<std::size_t N>
constexpr bool ContainsAsterisk(const char(&formatString)[N])
{
for (auto c : formatString)
{
if (c == '*')
{
return true;
}
}
return false;
}
You don't actually need to use string_view.
Unfortunately I can't explain to you why string_view doesn't work.
You already have answers on how else to do this so I wont add anything more to that but this answer will address
I don't understand how the variable is being read outside it's lifetime, it's a literal (isn't it?) that I thought would be available at compile time.
Yes, a string literal is a compile time constant. The issue here is that a function parameter is not a compile time constant, even if it is initialized from one. To see why that is, lets start with the function
template <auto var>
auto foo()
{
if constexpr (var == 1)
return 1;
else
return 1.0;
}
This function template will have two different return types, but only one of them will ever be used in a specialization so you still follow the rule of one return type per function. Now if we allowed constexpr function parameters like
auto foo(constexpr int var)
{
if constexpr (var == 1)
return 1;
else
return 1.0;
}
This function will either return a int or a double, but you can't have one function that has different return types.
Related
I was trying to implement a certain type trait, but faced this following error.
Here is a simple program that shows the behavior:
#include <iostream>
template<typename T>
struct my_floating_point // just to make a case
{
// static constexpr bool value = std::is_floating_point_v<T>;
// THIS WORKS
static constexpr bool value = []()
{
if constexpr(std::is_floating_point_v<T>) { return true; }
else { return false; }
}; // compilation error
};
int main()
{
std::cout << my_floating_point<int>::value << std::endl;
std::cout << my_floating_point<double>::value << std::endl;
std::cout << my_floating_point<char>::value << std::endl;
}
The commented line works just fine.
However, the uncommented piece of code gives this warning with g++:
g++ -std=c++17 -O3 main.cpp -Wall -Wextra -pedantic
main.cpp: In instantiation of ‘constexpr const bool my_floating_point<int>::value’:
main.cpp:18:39: required from here
main.cpp:9:24: warning: the address of ‘static constexpr bool my_floating_point<int>::<lambda()>::_FUN()’ will never be NULL [-Waddress]
static constexpr bool value = []()
^~~~~
main.cpp:9:24: warning: the address of ‘static constexpr bool my_floating_point<int>::<lambda()>::_FUN()’ will never be NULL [-Waddress]
And running it outputs
1
1
1
What is wrong?
Note: clang++ for some reason doesn't give warning, but outputs the same.
[]()
{
// ...
}
A lambda expression evaluates to an instance of an anonymous type. That's what a lambda really is: an object whose type is unspecified. Attempting to assign an instance of this object to a bool is not valid C++.
The good news is that this anonymous type has an operator() overload, that just happens, accidentally, to return a bool. So, for example, this will work:
static constexpr bool value = []()
{
if constexpr(std::is_floating_point_v<T>) { return true; }
else { return false; }
}(); // compiles just fine.
Summary: Simplify to get a more readable warning message, then compare the message to a possibly better-recognized case. This is more of a work-through answer (teach to fish) than a direct explanation (give a fish).
This is one of the cases where really working at a minimal reproducible example can have benefits. I acknowledge that some of the complication was kept "just to make a case", but let's drop that for now.
The three lines in main each trigger the same warning, so simplify to just one of those lines. Preferably, we keep a line whose output is unexpected, such as the first of the three lines (int is not a floating point type, so my_floating_point<int>::value is intended to be false). That cuts the compiler's messages to a third of what they were and helps identify which messages go together (at this point, they all go together).
With only one type to consider, we no longer need to my_floating_point to be a template. Templates sometimes add a significant amount of insignificant detail to warnings (such as – in this case – the required from here message), so drop the template and replace std::is_floating_point_v<T> with std::is_floating_point_v<int>. This reduces the warning down to one message plus the indication of where the warning occurred.
One more simplification: take value outside the struct, allowing my_floating_point to be eliminated. Admittedly, this does not have much impact on the error message, but it does remove a red herring from the example code.
#include <iostream>
static constexpr bool value = []()
{
if constexpr(std::is_floating_point_v<int>) { return true; }
else { return false; }
}; // compilation warning
int main()
{
std::cout << value << std::endl;
}
prog.cc:7:1: warning: the address of 'static constexpr bool<lambda()>::_FUN()' will never be NULL [-Waddress]
7 | }; // compilation warning
| ^
Note that this is almost one of the lines from the question's compiler output. The only difference is the removal of my_floating_point<int>:: which corresponds nicely with the simplifications we did.
OK, now that we have the situation suitably simplified, let's compare the warning to one produced in a slightly different setup. Instead of a lambda, let's use an official function. The goal is to gain some basic (yet imprecise) understanding by by comparing similar scenarios.
Don't get hung up on "how would I think to do this?" This is something I knew to do because I recalled a remarkably similar warning from a different setup. The first part of this answer presented steps that I think are reasonable to expect from others. In contrast, this part of this answer requires familiarity with messages from the compiler.
#include <iostream>
bool fun()
{
if constexpr(std::is_floating_point_v<int>) { return true; }
else { return false; }
}
static constexpr bool value = fun; // compilation warning
int main()
{
std::cout << value << std::endl;
}
prog.cc:9:31: warning: the address of 'bool fun()' will never be NULL [-Waddress]
9 | static constexpr bool value = fun; // compilation warning
| ^~~
Again, the same warning that the address of [something] will never be NULL. (Perhaps you already see where this is going?) In this code, since the function is not invoked, the symbol fun becomes a pointer to the function. Assigning a pointer to a bool results in true if and only if the pointer is non-null. This particular pointer cannot be null because it is the address of something. So the compiler throws out a warning; the code is syntactically valid, but you probably meant to invoke the function (by adding parentheses just before the semicolon, as in fun() instead of just fun).
Similar mechanics are in play for the code with a lambda. When the lambda is not invoked, it can convert to a bool, becoming true if and only if there is a lambda. As in the function case, the result has to be true. The compiler throws out a warning; the code is syntactically valid, but you probably meant to invoke the lambda (by adding parentheses just before the semicolon).
static constexpr bool value = []()
{
if constexpr(std::is_floating_point_v<int>) { return true; }
else { return false; }
}(); // no compilation warning with the parentheses
Even better, the output is now 0, as intended.
OK, the short version is "add parentheses", but the real lesson of this answer is the usefulness of recognizing compiler messages. When a warning is worded similarly to one you've encountered before, try to replicate the warning you are familiar with. See if there are similarities that allow you to transfer a solution from the familiar case to the less familiar one.
Familiarity takes time, but it takes less time if you make it a goal. ;)
I was wondering if there's an elegant solution for the following issue:
Let's say I'd like to have a variable holding a value with a pretty complex type and would the compiler to automatically infer it's type, but declare first and give value later in the code because of initialization in an if statement.
For example:
{
auto a;
if (some predicate)
a = init_a(1);
else
a = init_a(2);
}
Obviously this code doesn't compile, but the I think that the compiler has all the information it needs to infer the type.
If 'a' was just an int, this was not a problem, but if the type is a complex template, I don't want to have to write it (or in some cases even know it).
Also, i wouldn't want to call the default constructor of a and then write over it.
Possible solutions:
Template the type of 'a'.
initialize 'a' using a lambda and move the predicate into the lambda.
Just write the type of 'a' instead auto.
Use a void pointer/shared_ptr and then init 'a' on the heap.
Each of these has its own drawbacks.
Is there a more elegant solution for it?
The compiler doesn't have infinite lookahead what is happening further on in the code. It only knows what's happening at the current statement. Therefore it can't deduce any types without an initializer.
If you don't know the return-type of init_a then you could use decltype:
decltype(init_a(1)) a;
You can also use a lambda call to initialize the variable:
auto a = [ /* Captures needed for the condition... */ ]()
{
if (some_condition)
return init_a(1);
else
return init_a(2);
}(); // Call the lambda immediately
Or, as mentioned in many comments, use the ternary conditional expression:
auto a = some_condition ? init_a(1) : init_a(2);
There's a technique called "Immediately Invoked Lambda Expression" that is using lambda to initialize a variable in a complex way. Using this approach your a can be const which improves const-correctness. More details here.
For a simple binary predicate, consider just using the ternary operator:
struct A { int a; };
A initA(int a) { return A{a}; }
bool somePredicate(int input) { return input == 42; }
int main() {
const auto input = 42;
const auto a = somePredicate(input) ? initA(1) : initA(2);
}
for more complex initialization logic (beyond a binary case), wrap the initialization logic in a lambda:
struct A { int a; };
A initA(int a) { return A{a}; }
bool somePredicate(int input) { return input == 42; }
int main() {
const auto input = 42;
const auto a = []() {
if (somePredicate(input)) { return initA(1); }
else if (input == 100) { return initA(100); }
else { return initA(2); }}();
}
Both these approaches come with additional possibility of making the variable to be initialized const.
If the return types of your lambda are different but convertible to some type then you can force the return type (note the -> is mandatory when specifying a return type):
auto a = [=]() -> ConvertedType {
if (some_predicate) {
return CovertibleType1(1);
} else if (other_predicate) {
return ConvertibleType2(2);
}
return ConvertibleType3(3);
}();
Though I realize this basically defeats the auto declaration...
I have tried to create a compile-time simple Key-Value map in C++. I'm compiling with /std:c++11.
(Using IAR compiler for embedded code and only cpp++11 is supported at the moment)
I've learnt a little bit about meta-programming.
I don't want my map to have a default value, if key is not found,
like this post: How to build a compile-time key/value store?
I want to get compiler error, if in my code I'm trying to get a value which is not stored in the map.
Here is what I've done:
#include <iostream>
template <int kk, int vv>
struct KeyValue
{
static const int k = kk, v = vv;
};
// Declaration
template <typename kv, typename...>
struct CompileTimeMap;
// Recursive Definition
template<typename kv, typename... rest>
struct CompileTimeMap<kv, rest...>
{
template<int k_input>
struct get
{
static const int val = (k_input == kv::k) ? kv::v : CompileTimeMap<rest...>::get<k_input>::val;
};
};
// Base Definition
template <typename kv>
struct CompileTimeMap<kv>
{
template<int k_input>
struct get
{
static const int val = (k_input == kv::k) ? kv::v;
};
};
// ----------------------------- Main -----------------------------
typedef CompileTimeMap<KeyValue<10, 20>, KeyValue<11, 21>, KeyValue<23, 7>> mymap;
int main()
{
// This calles should be ok !! :)
std::cout << mymap::get<10>::val << std::endl;
std::cout << mymap::get<11>::val << std::endl;
std::cout << mymap::get<23>::val << std::endl;
// This line should resolve a compile error !! (there is no key of 33)
std::cout << mymap::get<33>::val << std::endl;
}
I get the following error: error C2131: expression did not evaluate to a constant.
How can I make this work? Many thanks :)
Don't write a template metaprogram, where it is not necessary. Try this simple solution (CTMap stands for compile time map):
template <class Key, class Value, int N>
class CTMap {
public:
struct KV {
Key key;
Value value;
};
constexpr Value operator[] (Key key) const
{
return Get (key);
}
private:
constexpr Value Get (Key key, int i = 0) const
{
return i == N ?
KeyNotFound () :
pairs[i].key == key ? pairs[i].value : Get (key, i + 1);
}
static Value KeyNotFound () // not constexpr
{
return {};
}
public:
KV pairs[N];
};
constexpr CTMap<int, int, 3> ctMap {{ { 10, 20 }, { 11, 21 }, { 23, 7 } }};
static_assert (ctMap[10] == 20, "Error.");
static_assert (ctMap[11] == 21, "Error.");
static_assert (ctMap[23] == 7, "Error.");
// constexpr auto compilationError = ctMap[404];
You will get a compilation error, if you uncomment the last line (live demo). The compiler will direct you to the KeyNotFound () : line, from
which the reason of the failure should be obvious.
Remarks
The member variable pairs is made public, to make it possible to initialize the map with list-initialization.
The given N and the number of pairs that initialize CTMap should match. If N is less, you get a compilation error. If N is greater, zero-initialized pairs ({ 0, 0 }) will be silently added to pairs. Pay attention to this.
The (compiler generated) constructor does not check for duplicate keys. operator[] will find the first, but the intended usage is that you do not initialize CTMap with duplicate keys.
Recursion is not necessary in C++14. We can write a for loop in a constexpr function (live demo). The linked implementation gives another idea for giving a compiler error in case the key is not found: an exception is thrown. The member variable pairs is made private.
Intended to be used in compile time
This is a linear map, and parameters are passed by value. My intention was that the map will be used in compile time evaluated code, where this should not be a problem.
Note also that when evaluated in run time, this class won't give any feedback if the key is not found in the map.
Let's take a closer look of how ctMap[10] works in different situations. I have tried the following with three compilers (MSVC v19.24, clang 10.0.0, gcc 9.3).
constexpr int C = ctMap[10]; – The global constant C will be initialized with 20 even in debug builds. No computation is made during run-time. Note that to ensure, that the global will be created, you have to take its address somewhere. If you use the value of C, its value (20) will be substituted where it is used, and C won't be created in the object file even in debug builds.
int Foo () { return ctMap[10]; } – In debug builds operator[] will be called. In release builds MSVC inlines operator[] to Foo, i.e. eliminates one call, but the resulting code has linear complexity (the compiler is not forced to do the computation in compile time, and code optimization is poor in MSVC). Clang and gcc compiles a return 20;.
And this is how ctMap[404] works (with the same three compilers):
constexpr int C = ctMap[404]; – Does not compile, as mentioned above.
int Foo () { return ctMap[404]; } – The same remarks apply as for ctMap[10], but Foo will return 0. You cannot know, that 404 was not in the map. To get the compilation error, Foo has to be constexpr and forced to be evaluated in compile time by e.g. assigning it to a constexpr variable or an enumerator, using it in a template argument, as a size of a C array, in a static_assert, etc.
I tried to find a similar answered question in SO but without success.
Question is why it is considered as error to use at compile time known at compile time value of template parameter of known at compile time type? Common sense tells me, that this code can be OK. What is wrong in this case?
Thanks!
#include <array>
using Cont = std::array<int, 2>;
class A
{
Cont a_ = {};
public:
int& at(bool first)
{
static_assert(sizeof(a_) / sizeof(int) == 2); // OK
static_assert(a_.size() > 1); // error: non-constant condition for static assertion. error: use of 'this' in a constant expression
return a_[first ? 0 : 1];
}
};
at compiler explorer
UPDATE: it looks like dublicate but may be not because in the question under link the speech is about run-time evaluation, but here looks like a_.size() can be evaluated in compile-time.
UPDATE2 More clear example (after considering answers and comments)
#include <array>
using Cont = std::array<int, 2>;
// OK
void checkSize(const Cont& b)
{
static_assert(b.size() == 2);
}
class A
{
Cont a_ = {};
public:
constexpr void checkSize() const
{
Cont b = {};
static_assert(b.size() == 2); // OK
static_assert(sizeof(a_) / sizeof(int) == 2); // OK
static_assert(a_.size() == 2); // error: non-constant condition for static assertion. error: use of 'this' in a constant expression
}
};
shows that the problem in this is involved to evaluate a_.size(). But why it is needed there, while a_ is known by compiler as non-virtual type and size() can be evaluated in compile time, may be is another question, so I'll check first answer.
std::array::size, even though a constexpr function, isn't a static function. This means it requires an object instance to be invoked.
In this particular case, at isn't constexpr†, therefore this isn't either and in turn _a. Since _a isn't constexpr, the result of _a.size() isn't constexpr too.
† Even if it is, the body still isn't considered constexpr.
a_ is a member of the class A.
a_.size() is a simplification of this->a_.size() because size is not a static function, which means that in order to access a_, you have to access this.
this is a pointer to a class A and is NOT a compile time constant making your static_assert fail.
Using template is probably easier :
template<int N>
class B {
std::array<int, N> a_;
public:
int& at(bool first)
{
static_assert((sizeof(a_) / sizeof(int)) == 2, "Sizeof operator"); // OK
static_assert(N > 1, "Size method"); // No problem here
return a_[first ? 0 : 1];
}
};
Is there a way to make static_assert's string being dynamically customized and then displayed?
What I mean is something like:
//pseudo code
static_assert(Check_Range<T>::value, "Value of " + typeof(T) + " type is not so good ;)");
No, there is not.
However this does not matter so much, because static_assert are evaluated at compile-time, and in case of error the compiler will not only print out the message itself, but it will also print the instanciation stack (in case of templates).
Have a look at this synthetic example in ideone:
#include <iostream>
template <typename T>
struct IsInteger { static bool const value = false; };
template <>
struct IsInteger<int> { static bool const value = true; };
template <typename T>
void DoSomething(T t) {
static_assert(IsInteger<T>::value, // 11
"not an integer");
std::cout << t;
}
int main() {
DoSomething("Hello, World!"); // 18
}
The compiler does not only emits the diagnostic, but it also emits the full stack:
prog.cpp: In function 'void DoSomething(T) [with T = const char*]':
prog.cpp:18:30: instantiated from here
prog.cpp:11:3: error: static assertion failed: "not an integer"
If you know Python or Java and how they print the stack in case of exception, it should be familiar. In fact, though, it's even better, because you not only get the call stack, but you also get the arguments values (types here)!
Therefore, dynamic messages are not as necessary :)
The standard specifies the second argument of static_assert to be a string literal, so no chance for computation there as far as I can see (except for preprocessor macros).
A compiler could extend the standard and allow const-expressions of approporiate type in this position, but I have no idea if any compiler does.
As Matthieu said, it's not possible, but you can get some of the functionalities you're looking for by using macros:
#define CHECK_TYPE_RANGE(type)\
static_assert(Check_Range<type>::value, "Value of " #type " type is not so good ;)");
CHECK_TYPE_RANGE(float); // outputs "Value of float type is not so good ;)"