Say I'm making a general-purpose collection of some sort, and there are 4-5 points where a user might want to choose implementation A or B. For instance:
homogenous or heterogenous
do we maintain a count of the contained objects, which is slower
do we have it be thread-safe or not
I could just make 16 or 32 implementations, with each combination of features, but obviously this won't be easy to write or maintain.
I could pass in boolean flags to the constructor, that the class could check before doing certain operations. However, the compiler doesn't "know" what those arguments were so has to check them every time, and just checking enough boolean flags itself imposes a performance penalty.
So I'm wondering if template arguments can somehow be used so that at compile time the compiler sees if (false) or if (true) and therefore can completely optimize out the condition test, and if false, the conditional code. I've only found examples of templates as types, however, not as compile-time constants.
The main goal would be to utterly eliminate those calls to lock mutexes, increment and decrement counters, and so on, but additionally, if there's some way to actually remove the mutex or counters from the object structure as well that's be truly optimal.
Conditional computation before 17 was mostly about template specialization. Either specializing the function itself
template<> void f<int>(int) {
std::cout << "Locking an int...\n";
std::cout << "Unlocking an int...\n";
}
template<> void f<std::mutex>(std::mutex &m) {
m.lock();
m.unlock();
}
But this actually creates a rather branchy code (in your case I suspect), so a more sound alternative would be to extract all the dependent, type-specific, parts into static interface and define a static implementation of it for a particular concrete type:
template<class T> struct lock_traits; // interface
template<> struct lock_traits<int> {
void lock(int &) { std::cout << "Locking an int...\n"; }
void unlock(int &) { std::cout << "Unlocking an int...\n"; }
};
template<> struct lock_traits<std::mutex> {
void lock(std::mutex &m) { m.lock(); }
void unlock(std::mutex &m) { m.unlock(); }
};
template<class T> void f(T &t) {
lock_traits<T>::lock(t);
lock_traits<T>::unlock(t);
}
In C++17 if constrexpr was finally introduced, now not all branches do have to compile in all circumstances.
template<class T> void f(T &t) {
if constexpr<std::is_same_v<T, std::mutex>> {
t.lock();
}
else if constexpr<std::is_same_v<T, int>> {
std::cout << "Locking an int...\n";
}
if constexpr<std::is_same_v<T, std::mutex>> {
t.unlock();
}
// forgot to unlock an int here :(
}
Related
I would like to know if it is possible to have a for loop in compile time with runtime or even compile time limit condition in c++11?
I start with a silly try to find out what I need.
for (uint32_t i = 0; i < n; ++i)
{
templated_func<i>();
}
consider I have a class with a private member variable n, and I want to call a template function with a different number that iterates from 0 to n (for the case of runtime limit condition)
I've had studies on the "Template Metaprogramming" and "Constexpr If" (c++17) but I have not gotten any results, can anyone help me?
You can't have a for loop, but you can call N lots of templated_func
namespace detail {
template <template<uint32_t> class F, uint32_t... Is>
void static_for_impl(std::integer_sequence<uint32_t, Is...>)
{
F<Is>{}()...;
}
}
template <template<uint32_t> class F, uint32_t N>
void static_for()
{
detail::static_for_impl<F>(std::make_integer_sequence<uint32_t, N>{});
}
template <uint32_t I>
struct templated_caller
{
void operator()() { templated_func<I>(); }
}
int main()
{
static_for<templated_caller, 10>();
return 0;
}
Note that this is more general than what you asked for. You can simplify it to just
template <uint32_t... Is>
void call_templated_func(std::integer_sequence<uint32_t, Is...>)
{
templated_func<Is>()...;
}
int main()
{
call_templated_func(std::make_integer_sequence<uint32_t, N>{});
return 0;
}
but that's lengthy to repeat multiple times, and you can't pass a function template as a template parameter.
As you said you only had C++11 then you will not have std::make_index_sequence and will have to provide it. Also, the fold expression in Caleth's answer is not available until C++17.
Providing your own implementation of index_sequence and a fold expression in c++11 can be done in the following way,
#include <iostream>
template <size_t... Is>
struct index_sequence{};
namespace detail {
template <size_t I,size_t...Is>
struct make_index_sequence_impl : make_index_sequence_impl<I-1,I-1,Is...> {};
template <size_t...Is>
struct make_index_sequence_impl<0,Is...>
{
using type = index_sequence<Is...>;
};
}
template<size_t N>
using make_index_sequence = typename detail::make_index_sequence_impl<N>::type;
template<size_t I>
void templated_func()
{
std::cout << "templated_func" << I << std::endl;
}
template <size_t... Is>
void call_templated_func(index_sequence< Is...>)
{
using do_ = int[];
do_ {0,(templated_func<Is>(),0)...,0};
}
int main()
{
call_templated_func(make_index_sequence< 10>());
return 0;
}
This is essentially the same as the answer by #Caleth , but with the missing bits provided and will compile on c++11.
demo
demo on c++11 compiler
I would like to know if it is possible to have a for loop in compile time with runtime or even compile time limit condition in c++11
I don't know a reasonable way to have such loop with a runtime condition.
With a compile time condition... If you can use at least C++14, you can use a solution based on std::integer_sequence/std::make_integer_sequence (see Caleth answer) or maybe std::index_sequence/std::make_index_sequence (just a little more synthetic).
If you're limited with C++11, you can create a surrogate for std::index_sequence/std::make_index_sequence or you can create a recursive template struct with static function (unfortunately you can partially specialize a template function but you can partially specialize classes and structs).
I mean... something as follows
template <std::size_t I, std::size_t Top>
struct for_loop
{
static void func ()
{
templated_func<I>();
for_loop<I+1u, Top>::func();
}
};
template <std::size_t I>
struct for_loop<I, I>
{ static void func () { } };
that you can call
constexpr auto n = 10u;
for_loop<0, n>::func();
if you want to call templated_func() with values from zero to n-1u.
Unfortunately this solution is recursive so you can have troubles with compilers recursion limits. That is... works only if n isn't high.
How to pass lambda as template parameter.
For example this code
template<void (*callback)()>
void function() {
callback();
}
int main() {
function<[]() -> void { std::cout << "Hello world\n"; }>();
}
fails with error "invalid template argument for 'function', expected compile-time constant expression".
What I'm doing wrong.
Edit
I want to implement something like this
template<typename T,
T (*deserializer)(buffer *data),
void (*serializer)(T item, buffer *data)>
class Type {
public:
T item;
Type(T item) : item(item) {
}
Type(buffer *data) {
deserialize(data);
}
void serialize(buffer *data) {
serializer(item, data);
}
void deserialize(buffer *data) {
deserializer(data);
}
};
typedef Type<int, [](buffer* data) -> int { return -1; }, [](int item, buffer* data) -> void {}> IntType
typedef Type<long, [](buffer* data) -> long { return -1; }, [](long item, buffer* data) -> void {}> LongType
Lambdas in C++14, including their conversion to function pointers, are not constexpr.
In C++17, this is going to change. There are no stable compilers with that feature implemented that I'm aware of (if you find one, can you mention it in the comments below?).
At that point
constexpr auto tmp = []() -> void { std::cout << "Hello world\n"; };
function<+tmp>();
will definitely work. I am uncertain if
function<+[]() -> void { std::cout << "Hello world\n"; }>()
would work; there are some rules about lambdas in unevaluated contexts and inside template argument lists that may be separate from the constexpr lambda problem and may apply here.
We can hack it in C++14.
Create a template class that stores a static copy of a lambda and exposes a static function with the same signature (f_ptr) that calls that static copy of a lambda.
Instantiate it once globally with your lambda.
Pass a pointer to the f_ptr to your template.
So:
template<class L> struct stateless; // todo
template<class L> stateless<L> make_stateless(L l){return std::move(l);}
auto foo = make_stateless( []() -> void { std::cout << "Hello world\n"; } );
function< &foo::f_ptr >();
this is almost certainly not what you want.
The kind of template in the example does not take a type as a parameter, but rather a value. This value needs to be determinable at runtime, in order to instantiate the template, and the value of a lambda is not a compile time constant, so this method just wont do. The common way of sending functors to a function is:
template<typename Func>
void foo(Func&& f)
{
f();
}
And since you want a class template (please put such information in the question, not the comments), here is an example using classes:
#include <utility>
template<typename Func>
class MyClass
{
public:
MyClass(Func&& f) : f(f) {}
void Run() { f(); }
private:
Func f;
};
template<typename Func>
MyClass<Func> MakeMyClass(Func&& f)
{
return { std::forward<Func>(f) };
}
int main()
{
auto x = MakeMyClass( [](){} );
x.Run();
}
I have a class with a couple of fields, assignment c-tor and move c-tor:
class A{
std::vector<int> numbers;
int k;
public:
A(std::vector<int> &&numbers, const int k):
numbers(numbers), // fast
k(k)
{
// logic
}
A(const std::vector<int> &numbers, const int k):
A(std::move(std::vector<int>(numbers)), k) // copy-and-move vector
{
// empty
}
};
I want to keep logic in one c-tor and call it from others.
Also, I want to support fast move-semantics. And I have to explicitly copy-and-move arguments in the assignment c-tor.
Is there any way to avoid such nested construction and keep all advantages I've listed above?
You could delegate one constructor to the other:
struct A
{
A(const std::vector<int> & v) : A(std::vector<int>(v)) {}
A(std::vector<int> && v)
: v_(std::move(v))
{
// logic
}
// ...
};
The moving constructor is now as fast as it can be, and the copying constructor costs one more move than if you spell both constructors out. If you're willing to pay an extra move, though, you might as well just have a single constructor:
struct A
{
A(std::vector<int> v)
: v_(std::move(v))
{
// logic
}
};
The alternative is to put the common code into a function and call that from both constructors.
I had this whole story about my frustrating journey to finding out that an unordered map I was returning from a function was not in fact RVO'd even though I was certain it was at an earlier time that it was but irrelevant.
Is there a way to check if RVO is happening in any given function? Or like a list of do's and dont's to follow to get the outcome I desire?
Yes. Create hooks for the lifecycle methods of your class:
#include <iostream>
struct A{
A()
{ std::cout<<"Ctor\n"; }
A(const A& o)
{ std::cout<<"CCtor\n"; }
A(A&& o)
{ std::cout<<"MCtor\n"; }
~A()
{ std::cout<<"Dtor\n"; }
private:
int vl_;
};
A getA(){
A a;
return a;
}
int main(){
A b = getA();
return 0;
}
Now with RVO, b is the same object as a in getA so you'll only see
Ctor
Dtor
You can suppress RVO, e.g., by adding an additional return point:
return a;
return A{a};
or moving:
return std::move(a);
And then you'll see:
Ctor
Mctor
Dtor
Dtor
You can verify that RVO was used in all the places where it's important to you:
template<typename T>
struct force_rvo: T {
force_rvo() {}
using T::T;
force_rvo(const force_rvo &);
force_rvo(force_rvo &&);
};
force_rvo<std::map<int, int>> f() {
force_rvo<std::map<int, int>> m;
m[17] = 42;
return m;
}
int main() {
auto m = f();
return m[42];
}
The force_rvo type pretends to be copyable and movable, otherwise compiler would reject return m. But if any of these is actually used, linker will fail and tell you where exactly that happened. The wrapper is zero cost, but requires using it both on caller and implementation sides, which may not be very convenient.
If I have two classes D1 and D2 that both derive from class Base, and I want to construct a particular one based on say, a boolean variable, there are various well known techniques, eg use a factory, or use smart pointers.
For example,
std::unique_ptr<Base> b;
if (flag)
{
b.reset(new D1());
}
else
{
b.reset(new D2());
}
But this uses the heap for allocation, which is normally fine but I can think of times where it would be good to avoid the performance hit of a memory allocation.
I tried:
Base b = flag ? D1() : D2(); // doesn’t compile
Base& b = flag ? D1() : D2(); // doesn’t compile
Base&& b = flag ? D1() : D2(); // doesn’t compile
Base&& b = flag ? std::move(D1()) : std::move(D2()); // doesn’t compile
My intention is that D1 or D2 whichever is chosen is constructed on the stack, and its lifetime ends when b goes out of scope. Intuitively, I feel there should be a way to do it.
I played with lambda functions and found that this works:
Base&& b = [j]()->Base&&{
switch (j)
{
case 0:
return std::move(D1());
default:
return std::move(D2());
}
}();
Why it doesn’t suffer from the same issues as the others that do not compile I do not know.
Further, it would only be suitable for classes that are inexpensive to copy, because despite my explicit request to use move, it does I think still call a copy constructor. But if I take away the std::move, I get a warning!
I feel this is closer to what i think should be possible but it still has some issues:
the lambda syntax is not friendly to old-timers who havent yet
embraced the new features of the language ( myself included)
the copy constructor call as mentioned
Is there a better way of doing this?
If you know all the types, you can use a Boost.Variant, as in:
class Manager
{
using variant_type = boost::variant<Derived1, Derived2>;
struct NameVisitor : boost::static_visitor<const char*>
{
template<typename T>
result_type operator()(T& t) const { return t.name(); }
};
public:
template<typename T>
explicit Manager(T t) : v_(std::move(t)) {}
template<typename T>
Manager& operator=(T t)
{ v_ = std::move(t); return *this; }
const char* name()
{ return boost::apply_visitor(NameVisitor(), v_); }
private:
variant_type v_;
};
Note: by using variant, you no longer need a base class or virtual functions.
The way you are trying to do it, you are going to get a dangling reference. Having the std::move is just hiding that.
Generally I just structure the code so that the logic is in a separate function. That is, instead of
void f(bool flag)
{
Base &b = // some magic to choose which derived class to instantiate
// do something with b
}
I do
void doSomethingWith(Base &b)
{
// do something with b
}
void f(bool flag)
{
if (flag) {
D1 d1;
doSomethingWith(d1);
}
else {
D2 d2;
doSomethingWith(d2);
}
}
However, if that doesn't work for you, you can use a union inside a class to help manage it:
#include <iostream>
using std::cerr;
struct Base {
virtual ~Base() { }
virtual const char* name() = 0;
};
struct Derived1 : Base {
Derived1() { cerr << "Constructing Derived1\n"; }
~Derived1() { cerr << "Destructing Derived1\n"; }
virtual const char* name() { return "Derived1"; }
};
struct Derived2 : Base {
Derived2() { cerr << "Constructing Derived2\n"; }
~Derived2() { cerr << "Destructing Derived2\n"; }
virtual const char* name() { return "Derived2"; }
};
template <typename B,typename D1,typename D2>
class Either {
union D {
D1 d1;
D2 d2;
D() { }
~D() { }
} d;
bool flag;
public:
Either(bool flag)
: flag(flag)
{
if (flag) {
new (&d.d1) D1;
}
else {
new (&d.d2) D2;
}
}
~Either()
{
if (flag) {
d.d1.~D1();
}
else {
d.d2.~D2();
}
}
B& value()
{
if (flag) {
return d.d1;
}
else {
return d.d2;
}
}
};
static void test(bool flag)
{
Either<Base,Derived1,Derived2> either(flag);
Base &b = either.value();
cerr << "name=" << b.name() << "\n";
}
int main()
{
test(true);
test(false);
}
gives this output:
Constructing Derived1
name=Derived1
Destructing Derived1
Constructing Derived2
name=Derived2
Destructing Derived2
You can ensure you have enough space for allocating either on the stack with std::aligned_storage. Something like:
// use macros for MAX since std::max is not const-expr
std::aligned_storage<MAX(sizeof(D1), sizeof(D2)), MAX(alignof(D1), alignof(D2))> storage;
Base* b = nullptr;
if (flag)
b = new (&storage) D1();
else
b = new (&storage) D2();
You can make a wrapper type for aligned_storage that just takes two types and does the maximum of size/alignment of the two without needing to repeat yourself in the code using it. You can emulate aligned_storage for non-over-aligned types fairly trivially too if you need C++98 support. The custom type without over-aligned support would be something like:
template <typename T1, typename T2>
class storage
{
union
{
double d; // to force strictest alignment (on most platforms)
char b[sizeof(T1) > sizeof(T2) ? sizeof(T1) : sizeof(T2)];
} u;
};
And that can be given protections against copies/moves if you so wish. It can even be turned into a simplified Boost.Variant with relatively little work.
Note that with this approach (or some of the others), destructors will not be called automatically on your class and you must call them yourself. If you want RAII patterns to apply here, you can extend the example class above to store a deleter function that is bound during construction into the space.
template <typename T1, typename T2>
class storage
{
using deleter_t = void(*)(void*);
std::aligned_storage<
sizeof(T1) > sizeof(T2) ? sizeof(T1) : sizeof(T2),
alignof(T1) > alignof(T2) ? alignof(T1) : alignof(T2)
> space;
deleter_t deleter = nullptr;
public:
storage(const storage&) = delete;
storage& operator=(const storage&) = delete;
template <typename T, typename ...P>
T* emplace(P&&... p)
{
destroy();
deleter = [](void* obj){ static_cast<T*>(obj)->~T(); }
return new (&space) T(std::forward<P>(p)...);
}
void destroy()
{
if (deleter != nullptr)
{
deleter(&space);
deleter = nullptr;
}
}
};
// usage:
storage<D1, D2> s;
B* b = flag ? s.emplace<D1>() : s.emplace<D2>();
And of course that can all be done in C++98, just with a lot more work (especially in terms of emulating the emplace function).
How about
B&&b = flag ? static_cast<B&&>(D1()) : static_cast<B&&>(D2());
If you just need them to be freed when the reference goes out of scope, you could implement another simple class (maybe named DestructorDecorator) that points to the object (D1 or D2). And then you just have to implement ~DestructorDecorator to call the destructor of D1 or D2.
You haven't mentioned it, your flag is known at compile time?
As far as a compile-time flag is concerned, you can use template magic to deal with the conditional construction of the class:
First, declaring a template create_if which takes two types and a boolean:
template <typename T, typename F, bool B> struct create_if {};
Second, specializing create_if for true and false values:
template <typename T, typename F> struct create_if<T, F, true> { using type = T; };
template <typename T, typename F> struct create_if<T, F, false> { using type = F; };
Then, you can do this:
create_if<D1, D2, true>::type da; // Create D1 instance
create_if<D1, D2, false>::type db; // Create D2 instance
You can change the boolean literals with your compile-time flag or with a constexpr function:
constexpr bool foo(const int i) { return i & 1; }
create_if<D1, D2, foo(100)>::type dc; // Create D2 instance
create_if<D1, D2, foo(543)>::type dd; // Create D1 instance
This is valid only if the flag is known at compile time, I hope it helps.
Live example.