问题
I am having trouble understanding non-type template arguments and was hoping someone could shed 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 an error saying:
/tmp/conditional_templates.cc:13:12: required from here
/tmp/conditional_templates.cc:8:5: error: cast from ‘const char*’ to ‘int’ loses precision [-fpermissive]
T("hello");
^
But, can't the compiler detect that the non-type argument "a" is 1 and hence the else branch won't be taken? Or is that too much to expect? In which case, how do I accomplish something like this?
回答1:
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();
}
Now, this uses partial template specialization in order to provide alternative implementations for specific values of the template parameters.
Note that I've used a class, because function templates cannot be partially specialized
回答2:
I have to admit I honestly don't see the fundamental reason to do this, but its your code. Apart from the obvious bug (failure to provide parens for the function call in main()
, and the warning (loss of data converting a char address to int
), the bigger question regarding conditional inclusion is important.
If you have have code such as:
if (something)
{
do something
}
it obviously has to compile, and will not do so conditionally. That the something
is sourced from a non-type template parameter makes no difference. You need to get the logic out of an in-function if-expression and into a template-expansion controlling mechanic instead. Specialization is one such technique, 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. Of course you could punt and do much/all of this with preprocessor macros, but where's the fun in that?
回答3:
Seems that in your environment sizeof(int)
is different than sizeof(const char*)
.
In such case part of code: T("hello")
which is in fact int("hello")
tries to convert const char*
to int
. Compiler is complaining because precision would be lost in such a conversion.
To check the sizes of int
and const char*
:
std::cout << sizeof(int) << std::endl;
std::cout << sizeof(const char*) << std::endl;
else
branch won't be run when calling f<int, 1>()
but it does not mean that compiler will ignore errors within else
code.
来源:https://stackoverflow.com/questions/29814047/conditional-compilation-and-non-type-template-parameters