Conditional compilation and non-python template options

I was having trouble understanding non-type template arguments and was hoping someone could shed some light on this.

#include <iostream>

template<typename T, int a>
void f() {
  if (a == 1) {
    std::cout << "Hello\n";
  } else {
    T("hello");
  }
}

int main() {
  f<int, 1>;
}

      

When I compile this, I get the error:

/tmp/conditional_templates.cc:13:12:   required from here
/tmp/conditional_templates.cc:8:5: error: cast fromconst char*’ to ‘int’ loses precision [-fpermissive]
     T("hello");
     ^

      

But can't the compiler detect that the non-type "a" argument is 1, and therefore the else clause won't be taken? Or is it too much to expect? In which case, how do I accomplish something like this?

+3


source to share


3 answers


Try this instead:

#include <iostream>
template<typename T, int a>
struct A {
    void f() {
        T("hello");
    }
};

template<typename T>
struct A<T,1> {
    void f() {
        std::cout << "Hello\n";
    }
};


int main() {
  A<int,1> a;
  a.f();
  A<int,2> b;
  b.f();
}

      



This now uses partial template specialization to provide alternative implementations for specific template parameter values.

Note that I used a class because function templates cannot be partially specialized

+1


source


I have to admit that I honestly don't see an underlying reason for this, but this is your code. Apart from the obvious error (refusal to provide parsers for calling a function in main()

and warning (loss of data converting a char address to int

), the big question about conditional inclusion is important.

If you have some code like:

if (something)
{
    do something
}

      

it obviously needs to compile and will not do so conditionally. What is something

obtained from a non-python type template parameter is irrelevant. You should get the logic from the functional if statement and instead into the template extension control mechanism. Specialization is one such method, SFINAE is another:



#include <iostream>
#include <iomanip>
#include <type_traits>
#include <cstdint>

static const char* something = "something";

template<class T, bool a>
typename std::enable_if<a>::type f()
{
    std::cout << __PRETTY_FUNCTION__ << '\n';
    std::cout << something << '\n';
}

template<class T, bool a>
typename std::enable_if<!a>::type f()
{
    std::cout << __PRETTY_FUNCTION__ << '\n';
    std::cout << std::hex << T(something) << '\n';
}

int main()
{
    f<int, true>();
    f<intptr_t, false>();
}

      

Output

typename std::enable_if<a>::type f() [T = int, a = true]
something
typename std::enable_if<!a>::type f() [T = long, a = false]
100001f18

      

What you do in each is up to you. Sure, you could wander around and do a lot / all of this with preprocessor macros, but where's the fun?

+3


source


It seems that your environment sizeof(int)

is different from sizeof(const char*)

.

In this case, the piece of code: T("hello")

that is actually int("hello")

trying to convert const char*

to int

. The compiler is complaining because precision will be lost with such a conversion.

To check sizes int

and const char*

:

std::cout << sizeof(int) << std::endl;
std::cout << sizeof(const char*) << std::endl;

      

else

the branch won't run when called f<int, 1>()

, but that doesn't mean that the compiler will ignore errors in else

.

0


source







All Articles