默认模板参数的“重新定义”

8

我有一个奇怪的编译警告,使用Visual C++ 2010编译以下代码:

#include <iostream>

class test
{
    public:
        template<class obj>
        class inner
        {
        private:
            // Line 11:
            template<int index, bool unused = true> struct AttributeName;

        private:
            template<bool b>
            struct AttributeName<0,b>
            {
                static inline const char* get()
                {
                    return "prop";
                }
            };

        public:
            typedef AttributeName<0> propname;
        };
        typedef inner<test> description;
};

int main()
{
    test t;
    std::cout << test::description::propname::get(); // Line 32
    return 0;
}

警告:
file.cpp(11) : warning C4348: 'test::inner<obj>::AttributeName' : redefinition of default parameter : parameter 2 (with [ obj=test ])
file.cpp(11) : see declaration of 'test::inner<obj>::AttributeName' (with [ obj=test ])
file.cpp(32) : see reference to class template instantiation 'test::inner<obj>' being compiled (with [ obj=test ])

我不理解的是,AttributeName的“重新定义”与定义在同一行...听起来像是一个错误。
我注意到将inner变为非模板类可以消除警告。然而,这不是一个选项,因为真正的代码比这个测试用例更复杂并且需要进行模板化。
此外,如果将警告视为错误,则此代码将无法编译...
在GCC上编译时没有警告
为什么msvc会输出这样的警告,并且有没有解决方法? 编辑 以下修改:
template<int index, bool unused = true> struct AttributeName {};

似乎已经消除了警告。

给那位点踩的用户:请在评论中说明你为什么要点踩。 - Synxis
可能是重复的问题,参考 *C++模板函数默认值*。 - Peter Mortensen
@PeterMortensen 不对,真的不是重复的问题。你链接的那个问题涉及“函数参数”,而我的问题涉及“模板参数”。此外,我的问题是关于一个错误的…… - Synxis
1个回答

8

我猜这可能解决了它:

template<int index, bool unused = true> struct AttributeName;
template<int index, bool unused> struct AttributeName
{
};

我猜测前向声明被视为声明和“定义”,因为它看不到其他内容,所以即使是同一行,默认值也会被投诉为“重新定义”。 这可能是无意的,尽管2012年的行为相同。


那似乎很可能。但是,我并不真正理解“它无法看到其他任何东西”。 - Synxis
我必须承认,Christian,在想出与你相同的答案之前,我盯着这个推断看了一段时间。特别是像 test::description::propname::AttributeName::AttributeName::AttributeName::get() 这样的东西,在这个定义下是完全合法的。 - WhozCraig
顺便说一句,在 Mac 上使用 LLVM 编译器没有任何问题(预计默认情况下 Mac GCC 编译器也能正常工作)。 - WhozCraig
2
Synxis,请记住我不是C++甚至MSVC++专家。你的第11行是一个前向声明,你从未为它定义任何内容。然而,编译器实际上也不需要从中获取任何东西,除了知道它的存在,因为你对它进行了特化,所以通过编译器中的一些奇怪巧合,它找不到定义,回到声明中将其视为定义,并认为“嘿,缺省参数已经在声明中声明了,所以让我们发出警告”。就像读同一本书两次,抱怨你已经知道它了 :-) - Christian Stieber
可以确认这是一个错误。 - skyde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接