条件编译和非类型模板参数
Conditional compilation and non-type template parameters
我在理解非类型模板参数时遇到困难,希望有人能阐明这一点。
#include <iostream>
template<typename T, int a>
void f() {
if (a == 1) {
std::cout << "Hellon";
} else {
T("hello");
}
}
int main() {
f<int, 1>;
}
当我编译它时,我收到一个错误,说:
/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");
^
但是,编译器不能检测到非类型参数"a"是 1,因此不会采用 else 分支吗?还是期望太高了?在这种情况下,我如何完成这样的事情?
我不得不承认,老实说,我没有看到这样做的根本原因,但它是你的代码。除了明显的错误(未能为 main()
中的函数调用提供括号)和警告(将 char 地址转换为 int
的数据丢失)之外,关于条件包含的更大问题也很重要。
如果您有如下代码:
if (something)
{
do something
}
它显然必须编译,并且不会有条件地这样做。something
源自非类型模板参数没有区别。您需要将逻辑从函数中的 if 表达式中取出,改为转换为模板扩展控制机制。专业化是一种这样的技术,SFINAE是另一种技术:
#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>();
}
输出
typename std::enable_if<a>::type f() [T = int, a = true]
something
typename std::enable_if<!a>::type f() [T = long, a = false]
100001f18
你在每个地方做什么取决于你。当然,您可以使用预处理器宏进行大量/所有这些操作,但是其中的乐趣在哪里?
试试这个:
#include <iostream>
template<typename T, int a>
struct A {
void f() {
T("hello");
}
};
template<typename T>
struct A<T,1> {
void f() {
std::cout << "Hellon";
}
};
int main() {
A<int,1> a;
a.f();
A<int,2> b;
b.f();
}
现在,这使用部分模板专用化,以便为模板参数的特定值提供替代实现。
请注意,我使用了一个类,因为函数模板不能部分专用
似乎在您的环境中sizeof(int)
与sizeof(const char*)
不同。
在这种情况下,代码的一部分:实际上是int("hello")
T("hello")
尝试将const char*
转换为int
。编译器抱怨因为在这种转换中会丢失精度。
要检查int
和const char*
的大小:
std::cout << sizeof(int) << std::endl;
std::cout << sizeof(const char*) << std::endl;
调用else
分支时不会运行f<int, 1>()
但这并不意味着编译器将忽略else
代码中的错误。
在 2022 年,这不再是一个大秘密,但我仍然认为这值得一提。
使用constexpr 如果在 C++17 中您实际想要使用的工具到达了。模板化实体内每个丢弃的 constexpr if 语句在实例化模板时不会实例化。(例外情况适用)
您的代码段只需要稍作修改。(除了修复)主要是分支必须反转才能将麻烦的语句放入 constexpr if 语句中。
#include <iostream>
template<typename T, int a>
void f() {
if constexpr (a != 1) {
T("foo");
} else {
std::cout << "barn";
}
}
struct Printer
{
Printer(char const * const msg) {
std::cout << "Message: " << msg << 'n';
}
};
int main() {
f<int, 1>();
f<Printer, 0>();
}
这打印
bar
Message: foo
- 扩展C++生成的代码的模板参数类型名称
- 如何在 c++ 中定义接受不同参数类型的函数向量?
- 在 C++ 中运行时调用模板时,是否可以切换模板的参数类型?
- 将函数参数类型声明为 auto
- 将函数的参数 - 签名从使用 'std::function<T>' 转换为模板参数类型
- 在 C++17 中调用具有不同参数类型的构造函数
- 具有先前参数类型匹配的参数包
- 我想知道为什么"std::unique_ptr<int> foo(新 int)"是合法的,因为"std::<int>unique_ptr"要求输入参数类型应该是"int"?
- 将可变参数类型列表的扩展打包为复杂类型的初始值设定项列表 - 合法吗?
- MSVC 错误:4 个重载中的任何一个都无法转换所有参数类型
- 使用constexpr + auto作为返回和参数类型的奇怪类型推导
- 如何从第一个参数推断第二个参数类型?
- C++模板函数中,指定回调函子/lambda 的参数类型,同时仍允许内联?
- 如何用不同的参数类型和数字回调函数
- C++stoi:这两个重载都无法转换所有参数类型
- 为什么std::{container}::template不能推导其参数类型
- 为模板参数类型中的新对象分配内存
- 为指向成员模板参数的指针推导额外模板参数类型的紧凑方式
- 使用std::conditional中的模板来确定函数参数类型
- C++中的短参数类型