我注意到函数模板中静态变量初始化的一个奇怪的行为.请考虑以下示例:
MyFile * createFile()
{
std::cout << "createFile" << std::endl;
return nullptr;
}
template
void test(const T& t)
//void test(T t)
{
static MyFile *f = createFile();
}
void main()
{
test("one");
//test("two");
test("three");
}
只要f
在test
是静态的,我预计createFile
将只调用一次.但是,它被调用两次.
花了一些时间来解决这个问题,我注意到从参数中删除const引用来test
修复它.另一个有趣的事情是传递给函数的字符串的长度也会影响初始化:当参数的长度相等时,静态变量只初始化一次,否则会发生新的初始化.
有人可以解释一下吗?除了上面提到的解决方案/解决方案之外,我们非常欢迎.
文字"一"是一个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
.
证据在于布丁:
#include#include #include template 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 void test_mutable(T &t) { std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << std::endl; } template void test_const_ref(const T &t) { std::cout << __func__ << " for literal " << t << " T is a " << typeid(T).name() << std::endl; } template 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"); }
示例结果(clang):
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
这是一个带有demangled名称的版本(将在clang和gcc上编译):
#include#include #include #include #include std::string demangle(const char* name) { int status = -1; // enable c++11 by passing the flag -std=c++11 to g++ std::unique_ptr res { abi::__cxa_demangle(name, NULL, NULL, &status), std::free }; return (status==0) ? res.get() : name ; } template 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 void test_mutable(T &t) { std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << std::endl; } template void test_const_ref(const T &t) { std::cout << __func__ << " for literal " << t << " T is a " << demangle(typeid(T).name()) << std::endl; } template 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*