【问题标题】:Can I use a template to set array size?我可以使用模板来设置数组大小吗?
【发布时间】:2015-09-28 22:19:15
【问题描述】:

所以,我是使用模板的新手,我有一个问题。由于模板是在编译时处理的,而且数组大小必须在编译时设置,我可以使用模板来设置数组大小吗?

template<const size_t N> struct Stats {
    // Member functions (omitted).

    // The stats themselves.
    int stats[N];
};

class DudeWithStats {
    public:
        void setStats(int sts[], size_t sz, bool derived = false);

        // Other member functions (omitted).

    private:
        Stats<8> base;
        Stats<5> derived;

        // Other member variables (omitted).
};

void DudeWithStats::setStats(int sts[], size_t sz, bool drvd /* = false */) {
    for (int i = 0; i < sz; i++) {
        if (drvd) {
            derived.stats[i] = sts[i];
        } else {
            base.stats[i] = sts[i];
        }
    }
}

int main() {
    int arrBase[8] = { 10, 20, 10, 10, 30, 10, 15, 6 };
    int arrDerived[5] = { 34, 29, 42, 100, 3 };

    DudeWithStats example;
    example.setStats(arrBase, 8);
    example.setStats(arrDerived, 5, true);
}

我可以看到用newstd::vector 制作一个动态数组,但我很好奇这是否可行。

(是的,我知道const 在模板声明中毫无意义,至少对编译器而言。它主要用于文档。)

提前致谢。

(编辑:注意到我在 setStats()' 定义中有默认参数。修复了这个问题。修复了函数本身,我相信(以前从未直接复制数组)。)

(编辑:将其切换为 size_t。仍在努力让 setStats() 工作,我可能会坚持手动传递统计信息,而不是作为数组传递。)

(编辑:刚刚使用了一种解决方法来让 setStats() 工作。看起来有点尴尬,但对于测试代码来说已经足够了。)


感谢大家的回答和帮助。我会使用类似的东西来满足我的需要,并随着我的编码能力的提高而改进它。

【问题讨论】:

  • 你尝试的时候发生了什么?
  • 你的模板参数应该是size_t类型的
  • 如果你没有做错任何事情,它会起作用。只是通常,这些数组都是不同类型的,这很快就会变得很烦人。但如果这不是问题,这种方法是可以的。
  • 这种事情不管模板都行不通:derived.stats = sts; Arrays are not assignable。
  • 如果你使用std::array&lt;int, N&gt; stats;,那么你可以使用赋值运算符来复制数组。

标签: c++


【解决方案1】:

是的。是的,你可以。

template <size_t N>
void foo()
{
   // 100% standard-compliant and fine
   bool array[N] = {};
}

【讨论】:

    【解决方案2】:

    你对模板的东西是完全正确的。模板(也许也是?)很灵活,其系统(恕我直言)只能由 Haskell 比较。

    无论如何,GCC 不会喜欢你的代码:

    c.cpp:21:57: error: default argument given for parameter 2 of ‘void DudeWithStats::setStats(int*, bool)’ [-fpermissive]
     void DudeWithStats::setStats(int* sts, bool drvd = false) {
                                                             ^
    c.cpp:10:14: error: after previous specification in ‘void DudeWithStats::setStats(int*, bool)’ [-fpermissive]
         void setStats(int* stats, bool derived = false);
              ^
    

    默认参数只给出一次而且只有一次,把它从定义中去掉就可以了。

    c.cpp: In member function ‘void DudeWithStats::setStats(int*, bool)’:
    c.cpp:23:23: error: incompatible types in assignment of ‘int*’ to ‘int [5]’
             derived.stats = sts;
                           ^
    c.cpp:25:20: error: incompatible types in assignment of ‘int*’ to ‘int [8]’
             base.stats = sts;
                        ^
    

    谁说你的数组是可赋值的?出于某种原因,有memcpynew(&amp;base.stats),不是吗?

    c.cpp: In function ‘int main()’:
    c.cpp:34:13: error: request for member ‘setStats’ in ‘example’, which is of non-class type ‘DudeWithStats()’
         example.setStats(arrBase);
                 ^
    c.cpp:35:13: error: request for member ‘setStats’ in ‘example’, which is of non-class type ‘DudeWithStats()’
         example.setStats(arrDerived, true);
    

    ........

    教程骗了你!你不是在声明一个变量,而是一个函数!

    C++ 语法中存在歧义(至少从程序员的角度来看),这使得像 DudeWithStats example(); 这样的东西意味着“声明一个不带参数的函数(在其他地方定义),并返回一个 DudeWithStats”而不是“声明一个名为 exampleDudeWithStats 并默认初始化它”。

    为了以后的目的,使用DudeWithStats example;(带有no括号!)。而且,对于勇敢和符合标准的人来说,C++11 支持在DudeWithStats example{}; 中找到的这种明确的替代语法。这种语法确实避免了上面提到的歧义,以及it provide several other advantages,包括(甚至更多)令人困惑的most vexing parse problem 的解析。

    所以答案是...

    除了那些次要细节之外,您的代码和templates 的使用(在语法上)是正确的。 P.D:请您使用size_t 而不是unsigned const int 来维护每个人的心理健康,好吗?

    【讨论】:

    • 这个答案在不贬低支撑初始化的情况下会更好......我们中的许多人都喜欢它
    • @M.M:我不是想诋毁它,而是说我不喜欢它被决定的美学方式。在我看来,他们只是采用了最后一个可以解决这种歧义的符号对({}),并且没有考虑像 MyType myVariable -&gt; (firstArg, secondArg) 之类的东西。无论如何,它们在技术上仍然是优越的,我会进行编辑以避免进一步的误解。
    猜你喜欢
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 2011-01-14
    • 2010-10-11
    • 2011-04-04
    相关资源
    最近更新 更多