【问题标题】:Templated static member functions in C++C++ 中的模板化静态成员函数
【发布时间】:2011-11-27 13:51:52
【问题描述】:

我编写了一个简单的测试程序来尝试学习如何在 C++ 中使用模板静态成员函数。代码可以编译,但不能正常工作(打印出一些垃圾)。我想我使用了正确的语法。我读过thisthis 和其他一些东西,但仍然不知道我做错了什么。下面的代码:

#include <iostream>
using namespace std;

class Util {
public:
    Util();
    virtual ~Util();

    template <typename T> static void printTab(T tab[]);
};

template <typename T>
void Util::printTab(T tab[]) {
    for (unsigned int i=0; i<sizeof(tab)/sizeof(tab[0]); i++) {
        cout << tab[0] << " ";
    }
    cout << endl;
}

int main() {

    float tabFloat[5] {1, 2, 3, 4, 5};
    unsigned char tabChar[3] {1, 2, 3};

    Util::printTab(tabFloat);
    Util::printTab(tabChar);

    return 0;
}

任何提示表示赞赏。

【问题讨论】:

    标签: c++ templates static-methods


    【解决方案1】:

    您需要将大小作为另一个模板参数传递:

    #include <iostream>
    using namespace std;
    
    class Util {
    public:
        Util();
        virtual ~Util();
    
        template <typename T,int N> static void printTab(T (&tab)[N])
        {
            for (int i=0; i<N; i++) {
                cout << tab[i] << " ";
            }
            cout << endl;
        }
    };
    
    int main() {
    
        float tabFloat[5] {1, 2, 3, 4, 5};
        unsigned char tabChar[3] {1, 2, 3};
    
        Util::printTab(tabFloat);
        Util::printTab(tabChar);
    }
    

    【讨论】:

    • 将 size 作为模板参数并不是一个好主意。对于不同的 N 值,编译器会生成新代码,这会导致二进制文件膨胀
    • @hackworks 如果这是问题,那么内联它并让它调用一个非模板函数。
    • @hackworks 更好的方法是使用范围(将数组的开始和结束传递给函数)。然而,这不是被问到的。
    • 内联在这里没有帮助。编译器将每次调用具有不同 N 的 printTad() 视为不同的函数,并为每个函数执行模板扩展。
    • @hackworks template &lt;typename T,int N&gt; inline static void printTab(T (&amp;tab)[N]) { printTab(tab, N); } 函数是你的重载。这里没有开销。
    【解决方案2】:

    sizeof(tab)T* 的大小,它不会返回整个数组的大小。您需要将其作为另一个参数传递给函数。请参阅此处了解解释和另一种可能的解决方法:When a function has a specific-size array parameter, why is it replaced with a pointer?

    请注意,第二个printTab 不会输出可读字符。如果您想查看打印出来的内容,请尝试:

     unsigned char tabChar[3] {'1', '2', '3'};
    

    【讨论】:

    • 谢谢垫。我将 printTab 的实现更改为: cout
    【解决方案3】:

    试试怎么样,调用函数的时候需要发送数组的大小:

    #include <iostream>
    using namespace std;
    
    class Util {
    public:
        Util();
        virtual ~Util();
    
        template <typename T> static void printTab(T tab[], size_t sz);
    };
    
    template <typename T>
    void Util::printTab(T tab[], size_t sz) {
        for (unsigned int i=0; i<sz; i++) {
            cout << tab[i] << " ";
        }
        cout << endl;
    }
    
    int main() {
    
        float tabFloat[5] {1, 2, 3, 4, 5};
        unsigned char tabChar[3] {1, 2, 3};
    
        Util::printTab(tabFloat, sizeof(tabFloat)/sizeof(float));
        Util::printTab(tabChar, sizeof(tabChar)/sizeof(char));
    
        return 0;
    }
    

    【讨论】:

    • 我之前的答案来自记忆,而当前的答案来自尝试实际代码。想删除反对票吗?
    • 有更安全的宏来计算数组的大小见my answer here,无论如何绕过模板安全并引入错误风险是相当奇怪的。
    • @MatthieuM。当'N'成为模板参数时,编译器不会为'N'的不同值生成额外的代码吗?
    • 视情况而定。对于宏(C++03 兼容),它不会。请注意,该函数从未定义,因此我们只能在未评估的上下文中真正使用它(sizeofdecltype,...)。没有定义,没有代码。至于结构,没有虚方法,所以也没有RTTI信息。在constexpr 函数的情况下,它可能。不过,这个函数是内联的主要候选者,所以一旦你开始优化(O1 和更多),它应该被内联。可能会发出一个定义,通过将其设为static,我们可能会对其进行修剪:一旦内联就不再引用。
    • 但问题是,这真的重要吗?这样的函数只有几个字节。几个字节的从未读过的内存。这是为永远不会弄错大小而付出的便宜代价,当然比跟踪缓冲区溢出更便宜。
    【解决方案4】:

    我会将 T 的元素数量作为函数参数传递或使用 STD 容器,例如 Vector。

    您的 for 循环只是打印第一个元素 tab[0] 而不是 tab[i]

    你的 tabFloat 和 tabChar 初始化丢失了=

    float tabFloat[5] {1, 2, 3, 4, 5}; 
    unsigned char tabChar[3] {1, 2, 3};
    

    (我也会使用 65、66、67 而不是 1、2、3 来提高您测试中控制台的可读性)

    float tabFloat[5] = {1, 2, 3, 4, 5}; 
    unsigned char tabChar[3] = { 65, 66, 67}; 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-30
      • 1970-01-01
      • 1970-01-01
      • 2011-04-11
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      • 2012-02-02
      相关资源
      最近更新 更多