首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++中模板声明中的范围和默认参数:澄清标准

C++中模板声明中的范围和默认参数:澄清标准
EN

Stack Overflow用户
提问于 2015-06-06 06:41:26
回答 2查看 702关注 0票数 6

为了提高对主题的理解,我正在阅读关于模板的C++14标准部分,无意中发现了这个特殊的规则:

§14.1

12在同一范围内,两个不同的声明不应给模板参数默认参数。示例:模板类X;模板类X{/∗.∗/ };//错误-结束示例

在我(相对不知情的)阅读中,“相同范围”的规范意味着能够从定义模板的地方在不同的范围中声明模板。

根据这篇关于多布斯博士的文章

C++确定了五种作用域:函数、函数原型、本地、命名空间和类。

我的理解是:

  • 函数&(我假设函数原型,因为它只将过去的函数扩展到声明)作用域不能包含模板声明
  • 本地范围属于函数范围,因此具有与上面相同的限制。
  • 在该类声明之外,您不能(重新)声明类的任何成员。

因此,允许在定义的作用域之外声明的潜在奇怪情况(可能使用更改的默认参数,取决于范围!)似乎完全落在了命名空间范围的肩膀上。我做了一些实验:

[柯尔鲁]

命令:

代码语言:javascript
复制
g++ -std=c++1z -O2 -Wall -pedantic -pthread main.cpp && ./a.out

代码:

代码语言:javascript
复制
#include <iostream>

namespace math{ 

    template <int I, int J>
    struct Plus{
        constexpr static int Value_ = I + J;
    };

    template <int I, int J = 5>
    struct Minus; // template declaration.

}

// global-scope template declaration?
//template <int I, int J>
//struct math::Minus; // error: does not name a type (if no declaration @ line 9)
                      // error: invalid use of math::Minus w/o argument list
                      //                             (if declaration @ line 9)


namespace math{

    template <int I, int J>
    struct Minus{
        static int value();
    };

    namespace{ // anonymous namespace

        //template <int I, int J = 5>
        //struct Minus; compiles, but is a declaration of another class,
                       // which I assume hides the math scope class

        // error: incomplete type--I assume this means the above 
        // doesn't declare math::Minus, but math::<anon>::Minus
        //constexpr int twominus5= Minus<2>::value(); 

    } // end anonymous namespace

} // end math namespace

//template <int I, int J>
//class math::Minus; // error: invalid use of math::Minus w/o argument list

template <int I, int J>
int math::Minus<I,J>::value(){return I - J;}


int main()
{
    std::cout 
        << math::Minus<5,1>::value() << std::endl
        << math::Minus<0>::value() << std::endl;
}

输出:

代码语言:javascript
复制
4
-5

...and声明规则似乎符合我在阅读这个标准的小片段之前的预期。很明显,我的理解是错误的。这是因为我最初阅读了c++标准的模板默认参数声明子句,还是我忽略了一些在其本机作用域之外声明模板的方法?

当然,这种语言的一个奇怪的角落(如果它确实存在的话)应该谨慎谨慎地使用,特别是因为它会改变其他部分指定的模板的行为,这取决于最适用的范围(它会引起名称冲突问题吗?在没有默认声明的范围内,如果模板定义的范围中有默认参数,那么一个完全限定的名称会如何解析?),但这引起了我的好奇心。

不管怎么说,我都会使用别名,因为这对每个人来说都不那么模糊,但正如我前面所说的:我现在很好奇,这是一个我完全没有刻意使用的奇怪的语言特性,还是一个我想象不到的非特性。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-06-06 11:52:38

我不确定我能完全理解你的想法,但我认为标准只是使用了过于清晰的措辞。这可能是为了澄清不同作用域中的“相同”模板可能具有不同的默认参数。示例:

代码语言:javascript
复制
namespace A
{
    template< int = 42 > struct X;
}

namespace B
{
    template< int = 123 > struct X;

    namespace C
    {
        template< int = 0 > struct X;
    }
}

当然,这些模板并不是同一个模板(即使初学者乍一看可能会这么认为),但它们是不同的模板。标准的措辞很可能就是为了强调这一点。

可以有不同默认值的一个示例是带有using的模板别名。

代码语言:javascript
复制
#include <iostream>
#include <type_traits>

namespace A
{
    template< int I = 42 >
    struct X { static void f() { std::cout << I << std::endl; } };
}

namespace B
{
    template< int I = 0 >
    using X = A::X< I >; 
}

int main()
{
    A::X<>::f();
    B::X<>::f();
    static_assert( std::is_same< B::X<>, A::X<0> >::value, "Oops" );
}

实例化

这方面的问题是,它一开始看起来与您的描述相匹配,但有趣的是,虽然B::X<>A::X<0>是相同的类型,但B::X目前并不是与A::X相同的模板。有关详细信息,请参阅这个答案

不过,有一个DR (CWG第1286期)可以解决这个问题。不同的默认参数OTOH是DR中提到的一个问题,因此即使DR被解决,它也可能不允许不同的默认值。

票数 2
EN

Stack Overflow用户

发布于 2015-06-06 13:52:18

相同模板的不同作用域中不同的默认参数的一个例子是,当它们在不同的翻译单元中声明时:

代码语言:javascript
复制
// x.hpp
template <class T> class X;

// a.cpp
#include "x.hpp"
template <class T = int> class X;

// b.cpp
#include "x.hpp"
template <class T = float> class X;

在这里,我们有两个转换单元创建两个范围,它们都声明相同的实体(类模板X)。在每个全局范围内,我们都有一个新的X声明,其中包含不同的默认模板参数。这是好的,因为他们在不同的范围。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30679813

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档