How are template arguments expanded - c++

I am confused about the expansion of this template [example one]. If bool b is checked at runtime in the constructor where is b stored ? is it put into the private data section [example two]? or does it become compile time and remove a branched based on the bool? or does it simply "paste" what was passed as a template argument into the if(b) [example 3]
Example one:
template<bool b>
class Test
{
public:
Test()
{
if(b)
{
// do something
}
else
{
// do something else
}
}
};
Example two:
class Test
{
public:
Test()
{
if(b)
{
// do something
}
else
{
// do something else
}
}
private:
bool b = true;
};
Example three:
//called with Test<true>
class Test
{
public:
Test()
{
if(true)
{
// do something
}
else
{
// do something else - probably removed due too compiler optimization
}
}
};

Example 3 is the snippet that more closely resembles what the compiler is doing. It's important to understand that example 2 is wrong, as the template parameter is evaluated at compile-time and not injected into the class as a field.
Doing if(b){ } else { } where b is a template bool parameter will require both branches of the if statement to be both parseable and well-formed, even if the compiler will very likely optimize out the branch that doesn't match b.
If you want guaranteed compile-time branch evaluation, and if you need only the taken branch to be well-formed, you can use if constexpr(...) in C++17:
if constexpr(b)
{
// do something
}
else
{
// do something else
}
...or implement your own static_if construct in C++14...
...or use an explicit template specialization in C++11.
I cover all of these techniques in my CppCon 2016 talk, "Implementing static control flow in C++14".

Related

Optimization for specific argument without template

I ran into some optimized code that is fast, but it makes my code ugly.
A minimal example is as follows:
enum class Foo : char {
A = 'A',
B = 'B'
};
struct A_t {
constexpr operator Foo() const { return Foo::A; }
};
void function_v1(Foo s){
if(s == Foo::A){
//Run special version of the code
} else {
//Run other version of the code
}
}
template<class foo_t>
void function_v2(foo_t s){
if(s == Foo::A){
//Run special version of the code
} else {
//Run other version of the code
}
}
int main(){
// Version 1 of the function, simple call, no template
function_v1(Foo::A);
// Version 2 of the function, templated, but call is still simple
function_v2(Foo::A);
// Version 2 of the function, the argument is now not of type Foo, but of type A_t
const A_t a;
function_v2(a);
}
For that last function call function_v2 will be instantiated with a specific version for A_t. This may be bad for the size of the executable, but in experiments, I notice that the compiler is able to recognize that switch == Foo::A will always evaluate to true and the check is optimized away. Using gcc, This check is not optimized away in the other versions, even with -O3.
I'm working on an extremely performance intensive application, so such optimizations matter. However, I don't like the style of function_v2. To protect against calling the function with the wrong type, I would have to do something like enable_if to make sure the function isn't called with the wrong type. It complicates autocompletion because the type is now templated. And now the user needs to keep in mind to call the function using that specifically typed variable instead of the enum value.
Is there a way to write a function in the style of function_v1, but still have the compiler make different instantiations? Maybe a slightly different coding style? Or a compiler hint in the code? Or some compiler flag that will make the compiler more likely to make multiple instantiations?
Is there a way to write a function in the style of function_v1, but still have the compiler make different instantiations?
If we expand your example a bit to better reveal the compiler's behavior:
enum class Foo : char {
A = 'A',
B = 'B'
};
struct A_t {
constexpr operator Foo() const { return Foo::A; }
};
void foo();
void bar();
void function_v1(Foo s){
if(s == Foo::A){
foo();
} else {
bar();
}
}
template<class foo_t>
void function_v2(foo_t s){
if(s == Foo::A){
foo();
} else {
bar();
}
}
void test1(){
function_v1(Foo::A);
}
void test2(){
function_v2(Foo::A);
}
void test3(){
const A_t a;
function_v2(a);
}
And compile with -O3, we get:
test1(): # #test1()
jmp foo() # TAILCALL
test2(): # #test2()
jmp foo() # TAILCALL
test3(): # #test3()
jmp foo() # TAILCALL
See on godbolt.org: https://gcc.godbolt.org/z/443TqcczW
The resulting assembly for test1(), test2() and test3() are the exact same! What's going on here?
The if being optimized out in function_v2() has nothing to do with it being a template, but rather the fact that it is defined in a header (which is a necessity for templates), and the full implementation is visible at call sites.
All you have to do to get the same benefits for function_v1() is to define the function in a header and mark it as inline to avoid ODR violations. You will effectively get the exact same optimizations as are happening in function_v2().
All this gives you is equivalence though. If you want guarantees, you should forcefully provide the value at compile time, as a template parameter:
template<Foo s>
void function_v3() {
if constexpr (s == Foo::A) {
foo();
}
else {
bar();
}
}
// usage:
function_v3<Foo::A>();
If you still need a runtime-evaluated version of the function, you could do something along these lines:
decltype(auto) function_v3(Foo s) {
switch(s) {
case Foo::A:
return function_v3<Foo::A>();
case Foo::B:
return function_v3<Foo::B>();
}
}
// Forced compile-time switch
function_v3<Foo::A>();
// At the mercy of the optimizer.
function_v3(some_val);
How about using template specialization:
template<class T>
void function_v2_other(T s){
//Run other version of the code
}
template<class T>
void function_v2(T s){
function_v2_other(s);
}
template<>
void function_v2(Foo s){
if(s == Foo::A){
//Run special version of the code
} else {
function_v2_other(s);
}
}

C++ conditional type at run time with templates

I have a template function that is specialized with two types, as:
class A () { /* ... */ };
class B () { /* ... */ };
template<class T>
void foo (T &out);
template<>
void foo<A> (A &out) { /* ... */ }
template<>
void foo<B> (B &out) { /* different code ... */ }
I either call foo with A or B depending on a run-time condition and I need to allocate either A or B before calling foo. After calling foo there needs to be other code that is the same with both A or B, resulting in something like this:
if (condition) {
A obj;
foo (obj);
/* code using obj */
} else {
B obj;
foo (obj);
/* same code using obj */
}
Since the only difference is in the declaration of obj, I would like to avoid repeating the same code, ideally like auto obj = condition ? A() : B(); which of course is not allowed run time. Is there any other way to obtain this in a clean way?
The common code could be a function template, or a generic lambda (depending on how much code there is and how readable the result:
if (condition) {
A obj;
foo (obj);
/* code using obj */
} else {
B obj;
foo (obj);
/* same code using obj */
}
Could transform into something like:
auto common_code = [](auto && obj) {
foo(obj);
/* code using obj */
};
if (condition) {
common_code(A{});
} else {
common_code(B{});
}
Another thing worth noting, foo does not need to be a template, and generally speaking, function template specializations are discouraged (as the specializations don't participate in overload resolution, and can be surprising).
You can just write two non-template foo functions, one that takes A& and the other that takes a B&. This is simpler and more obvious code.
If you're passing either an A or B object as an (in-)out argument for mostly common code with some select specialized behavior, simply add a function template that delegates the non-common work to foo and contains the common work by itself.
template <typename T, typename = std::enable_if_t<std::is_same_v<T, A> ||
std::is_same_v<T, B>>>
void do_non_const_things_with_a_or_b(T &obj) {
foo(obj); // specialized for A or B
// common code for A and B
}
void f(bool condition) {
if (condition) {
A obj;
do_non_const_things_with_a_or_b(obj);
} else {
B obj;
do_non_const_things_with_a_or_b(obj);
}
}

Extend object lifetime/scope from a `if constexpr` branch

Say we have the following code
struct MyClass
{
MyClass() = delete; // or MyClass() { }
MyClass(int) { }
void func() { }
};
int main()
{
if constexpr (std::is_default_constructible_v<MyClass>) {
MyClass myObj;
} else {
MyClass myObj(10);
}
myObj.func(); // Error
}
Here I am using if constexpr to determine whether the class is default-constructible (or not), and then create an object accordingly. In a way, I naively thought this would simplify the different branches down to just the one that's true, i.e.
if constexpr (true) {
/* instruction branch 1 */
} else if constexpr (false) {
/* instruction branch 2 */
}
simply becomes
/* instruction branch 1 */
But in reality, it is probably more like this
{
/* instruction branch 1 */
}
But then the question becomes (going to back to the the very first example), how can I can I keep myObj in scope outside the { ... }?
You can't extend the lifetime of an object with automatic storage duration beyond the scope in which it's created.
What you can do is create uninitialized storage outside your if block and create an object in that storage within the scope of the if. The easiest way to do that is probably std::optional:
template <typename T>
void foo() {
std::optional<T> obj;
if constexpr (std::is_default_constructible_v<T>) {
obj.emplace();
} else {
obj.emplace(10);
}
obj->func();
}
Live Demo
This does result in a small amount of overhead though, since std::optional has to hold an extra flag to determine if it holds an object or not. If you want to avoid that overhead you could manage the storage yourself:
template <typename T>
void foo() {
std::aligned_storage_t<sizeof(T), alignof(T)> storage;
T* ptr;
if constexpr (std::is_default_constructible_v<T>) {
ptr = new(&storage) T{};
} else {
ptr = new(&storage) T{10};
}
struct destroy {
destroy(T* ptr) : ptr_{ptr} {}
~destroy() { ptr_->~T(); }
T* ptr_;
} destroy{ptr};
ptr->func();
}
Live Demo
Note that in both cases I've moved the functionality to a function template. For if constexpr to discard a branch it must be dependent on a template parameter. If you try to do this directly in main the false branch will not be discarded and you will get an error complaining about a missing default constructor.
First, your code won't work. if constexpr really needs its condition to be dependent.
I'll fix it.
template<class MyClass>
void func() {
MyClass myObj = []{
if constexpr (std::is_default_constructible_v<MyClass>) {
return MyClass{};
} else {
return MyClass(10);
}
}();
myObj.func();
}
now
int main() {
func<MyClass>();
}
solves your problem.
Note that under c++17 rules, no copies or moves of MyClass occur in the above code.

How to combine negation with declaration inside if-statement?

When using C-style return codes to signal errors, it's pretty common to see code like this:
if (do_something()) {
do_something_else();
} else {
report_failure();
}
Sometimes, if one block is much larger than the other, you might want to reorder the "handle failure" block before the "do_something_else" block.
if (!do_something()) {
report_failure();
} else {
do_something_else();
}
(Or, when it really is C-code the codes may be such that 0 indicates success rather than failure, but let's ignore that.)
When I use C++ idioms like boost::optional or one of the proposed std::expected types, usually what I want to do is put a declaration inside the condition of the if statement:
if (auto ok = do_something()) {
do_something_else(*ok);
} else {
report_failure(ok.error());
}
I like to do this because this way, ok is strictly contained in scope, it's not visible outside the two blocks.
However, once I do it this way, I can't reorder the two branches if I want, which probably annoys me much more than it should, but still.
What I would really like is a syntax
if not (auto ok = do_something()) {
report_failure(ok.error());
} else {
do_something_else(*ok);
}
But to my knowledge that doesn't actually work.
Is there a trick to accomplish that?
C++17 will introduce this syntax:
if (auto ok = do_something(); !ok) {
report_failure(ok.error());
} else {
do_something_else(*ok);
}
Which is basically what you want.
It is in the feature-complete draft.
You can add an extra scope:
{
auto ok = do_something();
if (! ok) {
report_failure(ok.error());
} else {
do_something_else(*ok);
}
}
Personally I wouldn't add those braces as the scope should be clear from the rest of the code, if you have too much functionality in one function you should refactor the code anyways...
Alright, so here's a little class that does what you want. Dress it up however you like.
template <typename T>
struct not_optional_type: public optional <T>
{
typedef optional <T> base_type;
not_optional_type( const base_type& v ): base_type( v ) { }
operator bool () const { return !(base_type)(*this); }
T operator * () const { return *(base_type)(*this); }
};
template <typename T>
not_optional_type <T>
not_optional( const optional <T> && v )
{
return not_optional_type <T> ( v );
}
Use it as you would expect:
if (auto ok = not_optional( do_something() ))
fooey();
else
success( *ok );
I personally think the proposed if syntax modification is an abomination.
Well, a lot of dirty tricks come to mind involving macros, but, supposing you don't want to go there, here's a non-macro trick:
template <class T> class notter {
T d_t;
public:
notter(T &t) : d_t(t) {}
notter(T t) : d_t(t) {}
operator bool() { return !d_t; }
T &data() { return d_t; }
};
Now you can use it as:
if (notter<int> a = do_something()) {
report_failure();
}
else {
do_something_else(a.data());
}
This assumes that do_something returns an int. You may avoid naming the type with decltype like this:
if (notter<decltype(do_something())> a = do_something()) {
but in cases like this, that may be overkill.
You may tweak it to your needs, if, say, data() is too verbose for you, or you want just one of the constructors, or to make a more "drop-in replacement" for optional<> (as per comments from Duthomhas) or expected<> - you may employ template specialization.
Also, you can take hint from std::make_shared() and such:
template<class T> notter<T> make_notter(T t) { return notter<T>(t); }
and use it like:
if (auto a = make_notter(do_something())) {

C++ specialization, type_of or just typeid

I would like to know what is better to use in my situation and why. First of all I heard that using RTTI (typeid) is bad. Anyone could explain why? If I know exactly types what is wrong to compare them in a runtime? Furthermore is there any example how to use boost::type_of? I have found none searching through the mighty google :) Other solution for me is specialization, but I would neet to specialize at least 9 types of new method. Here is an example what I need:
I have this class
template<typename A, typename B, typename C>
class CFoo
{
void foo()
{
// Some chunk of code depends on old A type
}
}
So I need to rather check in typeid(what is I heard is BAD) and make these 3 realizations in example like:
void foo()
{
if (typeid(A) == typeid(CSomeClass)
// Do this chunk of code related to A type
else
if (typeid(B) == typeid(CSomeClass)
// Do this chunk of code related to B type
else
if (typeid(C) == typeid(CSomeClass)
// Do this chunk of code related to C type
}
So what is the best solution? I don't want to specialize for all A,B,C, because every type is has 3 specializations so I will get 9 methods or just this typeid check.
It's bad because
A, B and C are known at compile-time but you're using a runtime mechanism. If you invoke typeid the compiler will make sure to include metadata into the object files.
If you replace "Do this chunk of code related to A type" with actual code that makes use of CSomeClass's interface you'll see you won't be able to compile the code in case A!=CSomeClass and A having an incompatible interface. The compiler still tries to translate the code even though it is never run. (see example below)
What you normally do is factoring out the code into separate function templates or static member functions of classes that can be specialized.
Bad:
template<typename T>
void foo(T x) {
if (typeid(T)==typeid(int*)) {
*x = 23; // instantiation error: an int can't be dereferenced
} else {
cout << "haha\n";
}
}
int main() {
foo(42); // T=int --> instantiation error
}
Better:
template<typename T>
void foo(T x) {
cout << "haha\n";
}
void foo(int* x) {
*x = 23;
}
int main() {
foo(42); // fine, invokes foo<int>(int)
}
Cheers, s
Well generally solutions can be come up with without RTTI. It "can" show you haven't thought the design of the software out properly. THAT is bad. Sometimes RTTI can be a good thing though.
None-the-less there IS something odd in what you want to do. Could you not create an interim template designed something like as follows:
template< class T > class TypeWrapper
{
T t;
public:
void DoSomething()
{
}
};
then partially specialise for the functions you want to as follows:
template<> class TypeWrapper< CSomeClass >
{
CSomeClass c;
public:
void DoSomething()
{
c.DoThatThing();
}
};
Then in your class define above you would do something such as ...
template
class CFoo
{
TypeWrapper< A > a;
TypeWrapper< B > b;
TypeWrapper< C > c;
void foo()
{
a.DoSomething();
b.DoSomething();
c.DoSomething();
}
}
This way it only actually does something in the "DoSomething" call if it is going through the partially specialised template.
The problem lies in the code chunks you write for every specialization.
It doesn't matter if you write (lengthwise)
void foo()
{
if (typeid(A) == typeid(CSomeClass)
// Do this chunk of code related to A type
else
if (typeid(B) == typeid(CSomeClass)
// Do this chunk of code related to B type
else
if (typeid(C) == typeid(CSomeClass)
// Do this chunk of code related to C type
}
or
void foo()
{
A x;
foo_( x );
B y;
foo_( y );
C z;
foo_( z );
}
void foo_( CSomeClass1& ) {}
void foo_( CSomeClass2& ) {}
void foo_( CSomeClass3& ) {}
The upside of the second case is, when you add a class D, you get reminded by the compiler that there is an overload for foo_ missing which you have to write. This can be forgotten in the first variant.
I'm afraid this is not going to work in the first place. Those "chunks of code" have to be compilable even if the type is not CSomeClass.
I don't think type_of is going to help either (if it is the same as auto and decltype in C++0x).
I think you could extract those three chunks into separate functions and overload each for CSomeClass. (Edit: oh there are else if's. Then you might indeed need lots of overloads/specialization. What is this code for?)
Edit2: It appears that your code is hoping to do the equivalent of the following, where int is the special type:
#include <iostream>
template <class T>
bool one() {return false; }
template <>
bool one<int>() { std::cout << "one\n"; return true; }
template <class T>
bool two() {return false; }
template <>
bool two<int>() { std::cout << "two\n"; return true; }
template <class T>
bool three() {return false; }
template <>
bool three<int>() { std::cout << "three\n"; return true; }
template <class A, class B, class C>
struct X
{
void foo()
{
one<A>() || two<B>() || three<C>();
}
};
int main()
{
X<int, double, int>().foo(); //one
X<double, int, int>().foo(); //two
X<double, double, double>().foo(); //...
X<double, double, int>().foo(); //three
}
I think you've got your abstractions wrong somewhere.
I would try redefining A, B & C in terms of interfaces they need to expose (abstract base classes in C++ with pure virtual methods).
Templating allows basically duck-typing, but it sounds like CFoo knows too much about the A B & C classes.
typeid is bad because:
typeid can be expensive, bloats
binaries, carries around extra
information that shouldn't be
required.
Not all compilers support it
It's basically breaking the class hierarchy.
What I would recommend is refactoring: remove the templating, instead define interfaces for A, B & C, and make CFoo take those interfaces. That will force you to refactor the behaviour so the A, B & C are actually cohesive types.