簡體   English   中英

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");
}

示例結果(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 <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的答案的補充,它解釋了為什么使用不同的instanciations,很容易只強制一個,因為數組可以使用顯式模板實例衰減到指針:

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 ++不允許直接分配數組。

BTW, void main()糟糕 始終使用int main()和顯式返回。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM