C++模板函数中的静态变量初始化
C++ static variable initialization inside a template function
我注意到函数模板中静态变量初始化的奇怪行为。请考虑以下示例:
MyFile * createFile()
{
std::cout << "createFile" << std::endl;
return nullptr;
}
template <typename T>
void test(const T& t)
//void test(T t)
{
static MyFile *f = createFile();
}
void main()
{
test("one");
//test("two");
test("three");
}
只要test
中的f
是静态的,我就希望createFile
只被调用一次。但是,它被称为两次。
花了一些时间解决这个问题后,我注意到从 test
中的参数中删除 const 引用可以修复它。另一个有趣的事情是,传递给函数的字符串的长度也会影响初始化:当参数的长度相等时,静态变量只初始化一次,否则,会发生新的初始化。
有人可以解释一下吗?除了上述解决方案/解决方法之外,非常欢迎。
字面上的"一"是一个const char [4]
。
此代码:
test("one")
理想情况下,想打电话给test(const char (&)[4])
这适用于test(const T&)
(因为const char (&) [4]
可以绑定到const char (const&) [4]
)。
但它不适用于test(T t)
,因为您无法按值传递字符串文本。它们通过引用传递。
但是,const char[4]
可以衰减到const char*
,这可以匹配template<class T> void func(T t)
。
证据就在布丁里:
#include <cstdint>
#include <iostream>
#include <typeinfo>
template <typename T, std::size_t N>
void test_const(const T(&t)[N])
{
std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << " and N is " << N << std::endl;
}
template <typename T>
void test_mutable(T &t)
{
std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << std::endl;
}
template <typename T>
void test_const_ref(const T &t)
{
std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << std::endl;
}
template <typename T>
void test_copy(T t)
{
std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << std::endl;
}
int main()
{
test_const("one");
test_const("three");
test_mutable("one");
test_mutable("three");
test_const_ref("one");
test_const_ref("three");
test_copy("one");
test_copy("three");
}
示例结果 (刍峨):
test_const for literal one T is a c and N is 4
test_const for literal three T is a c and N is 6
test_mutable for literal one T is a A4_c
test_mutable for literal three T is a A6_c
test_const_ref for literal one T is a A4_c
test_const_ref for literal three T is a A6_c
test_copy for literal one T is a PKc
test_copy for literal three T is a PKc
这是一个名称被拆除的版本(将在clang和gcc上编译):
#include <cstdint>
#include <iostream>
#include <typeinfo>
#include <cstdlib>
#include <cxxabi.h>
std::string demangle(const char* name)
{
int status = -1;
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
template <typename T, std::size_t N>
void test_const(const T(&t)[N])
{
std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << " and N is " << N << std::endl;
}
template <typename T>
void test_mutable(T &t)
{
std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << std::endl;
}
template <typename T>
void test_const_ref(const T &t)
{
std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << std::endl;
}
template <typename T>
void test_copy(T t)
{
std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << std::endl;
}
int main()
{
test_const("one");
test_const("three");
test_mutable("one");
test_mutable("three");
test_const_ref("one");
test_const_ref("three");
test_copy("one");
test_copy("three");
}
预期输出:
test_const for literal one T is a char and N is 4
test_const for literal three T is a char and N is 6
test_mutable for literal one T is a char [4]
test_mutable for literal three T is a char [6]
test_const_ref for literal one T is a char [4]
test_const_ref for literal three T is a char [6]
test_copy for literal one T is a char const*
test_copy for literal three T is a char const*
@RichardHodges解释为什么使用不同实例的答案的补充,很容易只强制一个,因为数组可以使用显式模板实例化衰减到指针:
test<const char *>("one");
test<const char *>("two");
test<const char *>("three");
导致一次createFile
调用。
事实上(正如BoBTFish的评论所说),这正是你写的时候发生的事情:
template <typename T>
void test(const T t)
无论数组的大小如何,数组都会自动衰减到const char *
,因为C++不允许直接分配数组。
顺便说一句,void main()
不好。始终使用int main()
和显式返回。
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 模板基类中的静态变量
- 类和静态变量
- 不同作用域中的静态变量和全局变量
- 静态变量声明和定义
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 在类中继承静态变量?
- "local scope"中的 C++ 初始化静态变量
- 使用静态变量的递归调用的不同输出
- 复制文件流C++静态变量
- 跨模板化函数编译的静态变量
- C++编译器是否优化了顺序静态变量读取?
- C++,每个循环初始化一个新的静态变量
- (为什么)我们可以在初始化中将非静态类成员分配给静态变量吗?
- 这些语句是否等效(静态变量、常量变量和泛型)
- 程序如何知道静态变量是否需要初始化?
- 类外的静态变量实例化
- 无法解析静态变量
- 函数局部静态变量:从性能角度来看的优点/缺点
- 访问从 CPP 文件到其他头文件的静态变量