I got little confused with constepxt ctors..
Does the following is as just as fast (or faster)
while(true)
{
constexpr std::chrono::hours one_hour(1);
..
}
than (creating only one instance):
while(true)
{
static constexpr std::chrono::hours one_hour(1);
..
}
In other words, Does constexpr ctor means no runtime overhead whatsoever?
Does constexpr ctor means no runtime overhead whatsoever?
When in doubt, you can always check; for example:
#include <chrono>
template <long Long>
class dummy { };
int main() {
constexpr std::chrono::hours one_hour(1);
dummy<one_hour.count()> d;
}
The fact that it compiles means that one_hour is a compile time constant and as such, has no runtime overhead whatsoever.
Adding constexpr here won't make much difference because std::chrono durations and time points contain only a single integer member. In other words. the performance of initialization is the same as of int.
Related
For the following code snippet (using C++14 standard), can we declare setDataVectoras noexcept?
class Data {
public:
using Type = ...; // A class with a default move assignment operator. Or even just uint32_t
void setDataVector(std::vector<Type> &&input) // Can be declared as noexcept?
{
data = std::move(input);
}
private:
std::vector<Type> data;
};
In cppreference, it is mentioned that until C++17, the move assignment operator for std::vector is not noexcept.
vector& operator=( vector&& other );
Can it really throw even for trivial datatypes like integer?
What is confusing me is that move operations should be exception-safe but std::vector and std::string for example don't have a noexcept move assignment operators.
So, What am I missing here?
I was researching how to implement a compile time strlen for a toy project in this repo https://github.com/elbeno/constexpr when I noticed an unusual pattern of throws in some of the code. It seemingly does nothing, why would you do this?
namespace err {
extern const char * strlen_runtime_error;
}
constexpr int strlen(const char * str) {
return true ? constexpr_func() : throw strlen_runtime_error;
}
I got curious if it has any use what so ever but couldn’t find anything useful on my own. The extern err is undefined.
It seems it is trying to enforce the function being used only in compile time, according to this comment in another of the functions of the library:
// convenience function for inferring the string size and ensuring no
// accidental runtime encryption
template <uint64_t S, size_t N>
constexpr encrypted_string<S, N> make_encrypted_string(const char(&s)[N])
{
return true ? encrypted_string<S, N>(s) :
throw err::strenc_runtime_error;
}
However, as you point out, it is not doing anything here. Typically, that trick with the ternary operator in constexpr functions is used to trigger compile-time errors given a condition -- not to ensure all calls to the function are constant expressions. See constexpr error at compile-time, but no overhead at run-time for an explanation of that pattern.
If you need to ensure that the result was found out during compile time, you can easily assign the result to a constexpr variable:
constexpr int result = strlen("asd");
Using C++11, g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18).
Lets pretend I have a templated function (pardon my terminology if it isn't quite right).
I want to perform a "general" algorithm based on what was supposed to be compile-time instances of "field". Where the only things that really changed are these constants which I moved into trait classes (only added one here but imagine there are more). Originally I was declaring it as
constexpr field FIELD1{1};
However in C++11, non-type template params need to have external linkage (unlike C++14 which can have internal and external linkage?). So because not's in the same translation unit I needed to use extern in order to give it external linkage (sorry if I butchered that explanation also). But by defining it extern I can't define it using constexpr and it seems that losing that constexpr constructor this field is no longer a valid constant expression to qualify as a non-type template param.
Any suggestions if there is some way I can get around this? Open to a new method of doing things. Below is a simplified (incomplete, and non-compiling version to get the gist of the organization).
So the error I am seeing is along the lines of
error: the value of ‘FIELD1’ is not usable in a constant expression
note: ‘FIELD1’ was not declared ‘constexpr’
extern const field FIELD1;
Not quite sure what could be a best alternative.
I can get rid of the second error by removing the constexpr from the constructor. But then I don't know how to approach the constant expression issue.
field.H
struct field
{
int thingone;
constexpr field(int i):thingone(i){}
};
extern const field FIELD1;
field.C
#include "field.H"
const field FIELD1{0};
field_traits.H
#include "field.H"
template< const field& T >
class fieldTraits;
template< >
class fieldTraits<FIELD1>
{
public:
// Let's say I have common field names
// with different constants that I want to plug
// into the "function_name" algorithm
static constexpr size_t field_val = 1;
};
function.H
#include "field.H"
template< const field& T, typename TT = fieldTraits<T> >
void function_name()
{
// Let's pretend I'm doing something useful with that data
std::cout << T.thingone << std::endl;
std::cout << TT::field_val << std::endl;
}
So because not's in the same translation unit I needed to use extern in order to give it external linkage (sorry if I butchered that explanation also). But by defining it extern I can't define it using constexpr [...]
Per my comment, you can. It wouldn't work for you, but it's a step that helps in coming up with something that would work:
extern constexpr int i = 10;
This is perfectly valid, gives i external linkage, and makes i usable in constant expressions.
But it doesn't allow multiple definitions, so it can't work in a header file which is included in multiple translation units.
Ordinarily, the way around that is with inline:
extern inline constexpr int i = 10;
But variables cannot be declared inline in C++11.
Except... when they don't need to be declared inline because the effect has already been achieved implicitly:
struct S {
static constexpr int i = 10;
};
Now, S::i has external linkage and is usable in constant expressions!
You may not even need to define your own class for this, depending on the constant's type: consider std::integral_constant. You can write
using i = std::integral_constant<int, 10>;
and now i::value will do exactly what you want.
When initializing an atomic class member it requires a 'deleted' function, but adding it would make it no longer trivially copyable which is a requirement for an object/struct to be atomic. Am I just not understanding how to do this correctly, or is this a problem in the c++ standard?
Take the example below:
#include <atomic>
#include <cstdint>
template<typename T>
struct A
{
T * data;
std::atomic<uintptr_t> next;
};
template<typename T>
class B
{
std::atomic<A<T>> myA;
public:
B ( A<T> & a ) noexcept
{
myA.store(a, std::memory_order_relaxed );
}
};
int main ()
{
A<int> a;
B<int> b(a);
return 0;
}
Trying to compile this with g++ gives error: use of deleted function 'A<int>::A(const A<int>&)' myA.store(a, std::memory_order_relaxed);. My understanding of this error is that the atomic::store method is looking for that constructor in my struct A but not finding it.
Now here is what happens when I add that constructor:
#include <atomic>
#include <cstdint>
template<typename T>
struct A
{
T * data;
std::atomic<uintptr_t> next;
A(const A<T>& obj) { }
A( ) { }
};
template<typename T>
class B
{
std::atomic<A<T>> myA;
public:
B ( A<T> & a ) noexcept
{
myA.store(a, std::memory_order_relaxed );
}
};
int main ()
{
A<int> a;
B<int> b(a);
return 0;
}
I no longer receive the above compiler error but a new one coming from the requirements of the atomic class required from 'class B<int>' .... error: static assertion failed: std::atomic requires a trivially copyable type ... In other words by adding the used-defined constructors I have made my struct A a non-trivially copyable object which cannot be initialized in class B. However, without the user-defined constructors I cannot use the store method in myA.store(a, std::memory_order_relaxed).
This seems like a flaw in the design of the std::atomic class. Now maybe I am just doing something wrong because I don't have a lot of experience using C++11 and up (I'm old school). Since 11 there have been a lot of changes and the requirements seem to be a lot stricter. I'm hoping someone can tell me how to achieve what I want to achieve.
Also I cannot change std::atomic<A<T>> myA; to std::atomic<A<T>> * myA; (changed to pointer) or std::atomic<A<T>*> myA;. I realize this will compile but it will destroy the fundamental design of a class I am trying to build.
The problem here resides in the fact that std::atomic requires a trivially copiable type. This because trivially copyable types are the only sure types in C++ which can be directly copied by copying their memory contents directly (eg. through std::memcpy). Also non-formerly trivially copyable types could be safe to raw copy but no assumption can be made on this.
This is indeed important for std::atomic since copy on temporary values is made through std::memcpy, see some implementation details for Clang for example.
Now at the same time std::atomic is not copy constructible, and this is for reasonable reasons, check this answer for example, so it's implicitly not trivially copyable (nor any type which contains them).
If, absurdly, you would allow a std::atomic to contain another std::atomic, and the implementation of std::atomic contains a lock, how would you manage copying it atomically? How should it work?
if you do this:
constexpr int LEN = 100;
LEN variable defined as const without need of typing const keyword.
It also have static storage, without need to type static keyword.
From the other hand, if we do same in class:
struct A{
constexpr static int SIZE = 100;
};
SIZE is still defined as const without need of typing const keyword,
However SIZE is not static data member.
You need to type static explicitly. If you don't there will be compilation error.
Question is:
What is the reason of need to explicitly type static?
static doesn't have same signification in both context :
for LEN, static means "only available in this compilation unit", so only internal linkage. It's a storage specifier
for A::SIZE, static means "it's a class member", so not bound to specific instances
constexpr in class context can refer to instance or class member or function, so compiler can't determine at your place if it's static or not, ie bound or not to a specific instance. It's same reasoning as const specifier. But, as you can imagine, it's a non-sense to have a non-static constexpr member, so it's forbidden. Example :
class A
{
int a;
constexpr A(int value): a(value) {}
// constexpr bound to a specific instance
constexpr int getDouble() const
{ return a*2; }
// constexpr not bound to a specific instance
static constexpr int getDouble(int b)
{ return b*2; }
}
constexpr in global context refers to something which will be calculated at compile time (or, for function, if not possible to calculate at compile time, which will be inlined), so no need of external linkage and so, comparable behavior as a static global variable or function (only comparable because, with compile time calculation or inlining, you also don't need internal linkage)
constexpr int a = 5; // Will be replace everywhere by value
/* If b is constexpr, calcul are done at compile time and result will be used
* else double is inlined, so no need of linkage at all
*/
constexpr int getDouble(int b)
{ return b * 2; }
constexpr should not imply static, because having constexpr
without static makes sense. Consider:
#include <iostream>
struct Dim
{
constexpr Dim(int a,int b) : a(a), b(b) {}
constexpr int Prod() const { return a*b; }
int a,b;
};
int main()
{
constexpr Dim sz(3,4);
int arr[ sz.Prod() ];
std::cout << sizeof(arr) << std::endl;
}
It should also not imply static outside of class definition
since static there means 'local to translation unit' and constexpr
does not require that.
I think you are confused about what static means at global scope, and your question is based on that misunderstanding.
LEN variable defined as const without need of typing const keyword.
Of course constexpr implies const, that shouldn't be surprising.
It also have static storage, without need to type static keyword.
N.B. a global variable always has static storage, because its lifetime is global. Adding the static keyword does not change that, what it does is give it internal linkage meaning it is not accessible by name outside the current translation unit.
That's the same rule for constexpr and const on global variables: a namespace-scope const variable implicitly has internal linkage (which is one of the many meanings of "static").
But a class-scope const variable does not have internal linkage, even if you add static to it. Marking a variable static means something completely different at namespace-scope and class-scope. It doesn't make sense to automatically add static to class members marked const or constexpr because that would mean something completely different than it does to variables at namespace-scope.
So constexpr implies const (obviously), and at namespace scope const implies internal linkage.
At class scope constexpr still implies const, but that doesn't have any effect on whether a member variable is a "class variable" or an "instance variable".