I've been recently getting into template wizardry and in particular CRTP. I know that templates are used to make the compiler generate code for us so I was wondering if it were possible to make a template "decide" which parts of a function we would like it to include for a particular class. For example if I have the following code:
crtp.h
#include <iostream>
using std::endl;
using std::cout;
template<class T>
class A {
public:
void func() {
constexpr unsigned short mask = T::GetMask();
if (mask & 1) {
/*
Do Something
*/
cout << "Mask 1" << endl;
}
if (mask & 1 << 3) {
/*
Do Something else
*/
cout << "Mask 2" << endl;
}
}
};
class B : public A<B> {
friend class A<B>;
protected:
static constexpr unsigned short GetMask() { return 0x0001; }
};
class C : public A<C> {
friend class A<C>;
protected:
static constexpr unsigned short GetMask() { return 0x0009; }
};
main.cpp
#include "ctrp.h"
#include <iostream>
#include <vector>
using std::cout;
using std::vector;
using std::getchar;
using std::endl;
int main() {
B b;
C c;
cout << "B:" << endl;
b.func();
cout << endl << "C:" << endl;
c.func();
getchar();
}
Which when executed produces:
B:
Mask 1
C:
Mask 1
Mask 2
This works great, does exactly what I want it to. The problem is from my standpoint the if statements should be unnecessary. As I am dealing with constant expressions the compiler should have everything it needs to simply skip the branching and know to execute the first part for class B and both parts for class C.
I would like to cash in on this and specifically tell the compiler to remove the sections that are unnecessary for the particular class to avoid unnecessary branching at runtime. Unfortunately I have no idea how to do this, any ideas? Thanks in advance
Edit
In response to some of the awesome suggestions C++17's constexpr if expression is a near perfect solution that I had no idea existed, but am unfortunately unable to use. I am limited to using C++14.
If you care about performance, the compiler will very likely optimize out all "dead" branches and even the if condition, if it can evaluate it during compile time.
What is worse, all the branches need to be well formed until C++17 constexpr if. In this case, you can "outsource" the functionality to special (static member) functions and use specialization to invoke the right one. See #R Sahu's answer for the example.
Emulating if/else at compile time using template metaprogramming does not work that way. You have to imagine if/else using a different mindset.
Instead of
if (mask & 1) {
/*
Do Something
*/
cout << "Mask 1" << endl;
}
if (mask & 1 << 3) {
/*
Do Something else
*/
cout << "Mask 2" << endl;
}
you'll have to use something along the lines of:
function1_selector<mask & 1>::dostuff();
function2_selector<mask & 1 << 3 >::dostuff();
where
template <bool> struct function1_selector
{
static void dostuff() { /* Do nothing */ }
};
template <> struct function1_selector<true> // Specialize for true
{
static void dostuff() { /* Do something useful */ }
};
Add code for function2_selector similarly.
Related
In the following code:
#include <iostream>
#include <type_traits>
// this code below won't compile unless at this point there is already
// a typename rate
// using rate = std::integral_constant<int, 10>;
template<typename rate=rate> void functionA()
{
static_assert(rate::value > 5);
std::cout << "functionA: " << rate::value << std::endl;
}
template<typename rate> void loop()
{
functionA<std::integral_constant<int, 50>>(); // => prints "functionA: 50"
functionA(); // <- I would like this call to infer loop's functions's rate template type (which would be 20)
}
void other()
{
using rate = std::integral_constant<int, 12>;
functionA(); // => prints "functionA: 12"
}
void bare_loop()
{
functionA(); // should give compile time-error: no 'rate' in semantic scope
}
int main() {
loop<std::integral_constant<int, 20>>();
return 0;
}
I would like to be able to write a templated function which has a default parameter value which remains undeclared until compilation is necessary.
The above shows the most minimal piece of code to express this idea.
What I'm trying to achieve is directly inspired by Lisp's variable capture mechanism (lexical and dynamic scope).
To be clear: this is entirely a compile-time problem and solution.
Is this possible in the current state of affaires of C++?
I am really not sure if I understood what you intended, but if you want is a function that could either take the parameter rate at compile time or at runtime, well, one possibility would be to use a default parameter in function "functionA", determined by the template parameter. So you can define the default in compile time, and override it in runtime if needed.
I leave an example below in case it helps, however I can't understand what it the desired use case, and it can be possibly
a bad design:
#include <iostream>
#include <cassert>
constexpr int infer() { return 123; }
const int MIN_RATE_LIM = 5;
template<int t_rate=infer()> void functionA(const int rate = t_rate)
{
assert(rate > MIN_RATE_LIM);
std::cout << "functionA: " << rate << std::endl;
}
template<int rate> void loop()
{
for(int i = 0; i < 10; i++ )
{
functionA<50>();
functionA<rate>();
functionA<rate>(12); // <- 12 will overlap the value 10 in this line
}
}
int main() {
loop<10>();
return 0;
}
C++ has is_base_of<Base,Derived>. However, this also includes “grandparent” types.
Is there a way to get have is_child_of<Parent,Child> functionality? The purpose is to use types as sentinel 'interface' markers in an SFINAE context, without being affected by sentinels that may or may not be added to parent types.
That is, the following output is expected to be "true, false". (The output with is_base_of is "true, true".)
#include <iostream>
#include <type_traits>
class A {};
class B : A {};
class C : B {};
int main()
{
std::cout << std::boolalpha;
std::cout << "a2b: " << std::is_child_of<A, B>::value << '\n';
std::cout << "a2c: " << std::is_child_of<A, C>::value << '\n';
}
C++ doesn't have reflection, child's storage contain's parent's storage and it's hard to draw a line between one subobject and another. Some metaprogramming must be dome, mimicking libraries similar to Qt or MFC\WFC
#include <iostream>
#include <type_traits>
#define DECLARE_CLASS(Name, ParentName) using Parent = ParentName;
#define PARENT_CLASS(Name) Name::Parent
class LibBase {
public:
DECLARE_CLASS(LibBase, void)
};
class A : public LibBase {
public:
DECLARE_CLASS(A, LibBase)
};
class B : public A {
public:
DECLARE_CLASS(B, A)
};
int main()
{
std::cout << std::boolalpha;
std::cout << std::is_same<PARENT_CLASS(B), A>::value << std::endl;
std::cout << std::is_same<PARENT_CLASS(B), LibBase>::value << std::endl;
}
Clearly this simple approach have pitfall that we don't get an error if class is not defined using our macro., and it is static only,
First issue can worked around by creating a "trait" nested class by declaration, which got name based on class name passed to DECLARE_OBJECT. This would make result of PARENT_CLASS(Name) unique, e.g.
#define DECLARE_CLASS(Name, ParentName) struct TraitsOf##Name { \
using Parent = ParentName; \
};
#define PARENT_CLASS(Name) Name::TraitsOf##Name::Parent
Second issue can be worked around by creating own RTTI function within macro-definition
Sadly form is_child_of<LibBase, A>::value is unattainable with this because macro substitution happens before template substitution. Perhaps some static registering approach can be used to give classes unique traits in wait how BOOST_TYPEOF does but getting rid of macrodefinitions in user code would be nigh-impossible.
In this sample code, there is two sentences showing the same static variable. The first one gives no ambiguity, but the second one does, why?
#include <iostream>
using namespace std;
struct A { static const char a = 'a'; };
struct B : public A { };
struct C : public A { };
struct G : public B, public C { };
int main()
{
G v;
cout << G::B::A::a << endl;
cout << v.B::A::a << endl;
}
GCC error (according to some comments, there's no ambiguity in clang):
main.cpp:15:18: error: 'A' is an ambiguous base of 'G'
cout << v.B::A::a << endl;
Code on coliru
This is clearly a bug in GCC, as a GCC maintainer recommends you report it. However, until it's fixed, you can use a nasty workaround like this:
std::cout << static_cast<B &>(v).A::a;
The advantage is this will help disambiguate if in a (complex) scenario that there are variables with the same name in one of the base classes.
Actually, I'm not sure if using the operator< or any other comparison operator other than operator== is even valid, but I've not seen anything to suggest otherwise. So assuming that is valid, is there a way of determining if an enum is valid using SFINAE?
While
std::is_signed<std::underlying_type<EnumType>::type>::value
is the portable solution, however it is not yet available in all commonly used compilers. From the question it's not clear whether you are also asking about enum class, or just about enum, but maybe this work-around will do the job:
#include <iostream>
#include <iomanip>
enum S : int {};
enum U : unsigned {};
enum class SC : int {};
enum class UC : unsigned {};
template< typename E >
struct is_enum_signed {
static const bool value = E(-1) < E(0);
};
int main()
{
std::cout << std::boolalpha
<< is_enum_signed<S>::value << std::endl
<< is_enum_signed<U>::value << std::endl
<< is_enum_signed<SC>::value << std::endl
<< is_enum_signed<UC>::value << std::endl;
}
Disclaimer: I haven't checked whether or not it is standard-conforming, I'm just trying to offer an alternative of which you need to verify applicability and correctness for your environment...
I found interesting question and decided to examine top answer in detail.
I asked myself why there needs structure and try to rewrote the code without it:
#include <iostream>
template <int N> void out(std::ostream& os) {
out<N-1>(os);
os << N << std::endl;
}
template <> void out<1>(std::ostream& os){
os << 1 << std::endl;
}
int main(){
out<100>(std::cout);
}
And then I tried to refactor the code.
I got something like this:
#include <iostream>
template <int N> void out() {
if (N != 1) {
out<N-1>();
std::cout << N << std::endl;
}
else {
std::cout << 1 << std::endl;
}
}
int main(){
out<100>();
}
I don't understand why this code didn't work.
Any ideas?
The problem is that the if condition is evaluated at run-time. When you get to the instantiation where N = 1, it doesn't know that the first block of the if statement won't execute. It proceeds to instantiate out<0> and so on. If we had a static if, this would be possible, but it probably won't happen very soon.
Templates are expanded during compilation while if statements are only checked during run-time which is a different later stage. In your case the compiler will try to expand indefinetely as there is no specific implementation of the function for a fixed value of N(that used to be 1).