注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

C++内置变量在STL中初始化  

2013-09-12 00:08:03|  分类: C/C++基础 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、一个小问题
想累加一下一组不连续的整数出现的频率,当然最为简单的方法就是使用一个map来累加它们出现的次数,简单的代码如下
map<int,int> mapAccum;
for (input())
{
 mapAccum[item] += itemCount;
}
看起来比较简练,但是回头看看感觉有些忐忑,主要是这个mapAccum[item]在不存在的时候会创建一个key值为该内容的map项,但是这个新创建的map项的数值是不是一定是零呢?如果不是那么这个累加由于初始值都不正确,中间累加的过程再华丽也得不出个正确的结果。
二、gcc对于stl的实现
      mapped_type&
      operator[](const key_type& __k)
      {
    // concept requirements
    __glibcxx_function_requires(_DefaultConstructibleConcept<mapped_type>)

    iterator __i = lower_bound(__k);
    // __i->first is greater than or equivalent to __k.
    if (__i == end() || key_comp()(__k, (*__i).first))
          __i = insert(__i, value_type(__k, mapped_type()));
    return (*__i).second;
      }
这里的mapped_type对于我们这里的例子,就是一个int类型,当然key值也是int类型。所以根据泛型编程,这里相当与添加的新节点的类型就是一个int()的变量,这种用法比较少见,所以我在网上搜索了一下,大致的意思是对C++语言内置的基础类型,如果使用 type() 的形式,相当于一个static_cast<type>0的形式。由于网络上误人子弟的段子(例如大家现在正在看的这篇文章)比较多,所以我查了下《the C++ programming language》,在里面找到了这个作者(C++之父)关于这个的说明:在 6.2.8节中
the value of anexplicit use of the constructor for a built_in type is 0 converted to that type。
所以说网上的说法是靠谱的,进而说明map新添加项的初始值是零,最终说明上面的累加方法是正确的。
三、顺便又翻了翻这本书
国外书籍的优点就是后面的索引非常完善而详细,我看这个内容的时候就是在书的最后索引中找到大致位置。反观国内的很多数目,根本没有索引,对于国外书籍的翻译,把本来有原著中有的索引也给翻译丢掉了,这就是所谓的节操碎了一地吧。
然后看到了一个关于if中可以定义新变量的用法,就好象是在for循环中定义变量一样,这个变量的作用范围在if的两个分支中都可以使用,但是过了这个范围其作用域就会消失。大致的意思是
[root@Harry ifvar]# cat ifvar.cpp
#include <stdio.h>

int DoSomething();
int DoNothing()
{
    if(int iRet = DoSomething())
    {
        printf ("%s %d",__FUNCTION__,iRet);
    }
    printf("%d\n", iRet);
}
[root@Harry ifvar]# gcc -c ifvar.cpp
ifvar.cpp: In function ‘int DoNothing()’:
ifvar.cpp:10: error: ‘iRet’ was not declared in this scope
[root@Harry if
个人认为这是一个很好的方法,可以尽量减少变量的作用范围,而且是标准C++支持的语法,奇怪的是从来没有见过有人这么用,不知道是为什么。
四、又看了看gcc一些编译时检查
在对下标取值的重载函数中,其中添加了一个要求函数必须是有缺省构造函数的,里面的语句大致如此实现
    // concept requirements
    __glibcxx_function_requires(_DefaultConstructibleConcept<mapped_type>)
其中的模板定义如下,当然还有一些对于类型必须是可复制、可拷贝等类型的实现,这些只是通过定义新的类型模板实例化来确定是否满足这些条件,这里定义的函数并没有真正执行。
  template <class _Tp>
  struct _DefaultConstructibleConcept
  {
    void __constraints() {
      _Tp __a _IsUnused;                // require default constructor
    }
  };
……
  template <class _Tp>
  struct _CopyConstructibleConcept
  {
    void __constraints() {
      _Tp __a(__b);                     // require copy constructor
      _Tp* __ptr _IsUnused = &__a;      // require address of operator
      __const_constraints(__a);
    }
    void __const_constraints(const _Tp& __a) {
      _Tp __c _IsUnused(__a);           // require const copy constructor
      const _Tp* __ptr _IsUnused = &__a; // require const address of operator
    }
    _Tp __b;
  };

五、以struct作为map的key类型
以结构类型作为map的key类型,此时编译时就会有错误,因为map需要一个键值大小比较的功能,这个功能函数为map模板的第三个参数,只是这个参数在使用基本结构的时候,编译器能够自动识别基本类型的比较方法,而对于用户自定义的类型,此时需要定义相应的比较函数。看一下map的第三个参数的定义方法
  template <typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
            typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > >

  /// One of the @link s20_3_3_comparisons comparison functors@endlink.
  template <class _Tp>
    struct less : public binary_function<_Tp, _Tp, bool>
    {
      bool
      operator()(const _Tp& __x, const _Tp& __y) const
      { return __x < __y; }
    };
1、特殊化自定义类型的less函数
如此说来,实例化一下std的less函数类型就可以,不过这个实例化必须定义在std namespace内部,放在外面编译无法通过,具体原因不详,不过网上可以搜到说明,所以不用惊诧,大致代码如此:
[root@Harry mapless]# cat mapless.cpp
#include <map>
using namespace std;
struct messer
{
    int ifirst;
    int isecond;
};

namespace std
{
template<>
struct less<messer>
{
bool operator() (const messer & rlhs, const messer &rrhs) const
{
    return true;
}
};
}
int usage()
{
std::map<messer, int> mapMess;
}
2、重载全局 bool operator< (const T&, const T&)const
[root@Harry mapless]# cat globaloper.cpp
#include <map>
using namespace std;
struct messer
{
    int ifirst;
    int isecond;
};

bool operator<(const messer & rlhs, const messer &rrhs)
{
    return true;
}

int usage()
{
std::map<messer, int> mapMess;
}

[root@Harry mapless]# gcc globaloper.cpp -c
[root@Harry mapless]#
3、类内部定义操作符
[root@Harry mapless]# cat globaloper.cpp
#include <map>
using namespace std;
struct messer
{
    int ifirst;
    int isecond;
    bool operator<(const messer & rrhs) const
    {
        return true;
    }
};

int usage()
{
std::map<messer, int> mapMess;
}

[root@Harry mapless]# gcc globaloper.cpp -c
明显地,这种方法更加的简洁和直观,它把定义尽量限制在了类的内部。这也体现了C++的常规变量搜索路径,首先是类内部搜索,然后所在作用域,然后全局搜索,所以大部分的问题都可以在类的内部解决。
六、模板特殊化语法
1、结构类模板
14.6 Class template specializations [temp.class.spec]
1 A primary class template declaration is one in which the class template name is an identifier. A template declaration in which the class template name is a templateid, is a partial specialization of the class template named in the templateid. 主模板为模板名为单一的标志符,对应的,特例化类定义中名字为template id,也就是后面紧跟了一对尖括号,其中为模板参数。
The primary template shall be declared before any specializations of that template.
2 [Example:
3 template<class T1, class T2, int I> class A { }; // #1
template<class T, int I> class A<T, T*, I> { }; // #2
template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3
template<class T> class A<int, T*, 5> { }; // #4
template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5
2、函数类模板
A、函数后确定模板参数
14.10.1 Explicit template argument specification [temp.arg.explicit]
1 Template arguments can be specified in a call by qualifying the template function name by the list of templatearguments exactly as template arguments are specified in uses of a class template. [Example:
void f(Array<dcomplex>& cv, Array<int>& ci)
{
sort<dcomplex>(cv); // sort(Array<dcomplex>)
sort<int>(ci); // sort(Array<int>)
}
and
template<class U, class V> U convert(V v);
void g(double d)
{
int i = convert<int,double>(d); // int convert(double)
char c = convert<char,double>(d); // char convert(double)
}
一种方法是在函数后面加上类型模板中缺少的函数类型,明确说明是使用哪个函数。
B、函数调用时参数推导
14.10.2 Template argument deduction [temp.deduct]
1 Template arguments that can be deduced from the function arguments of a call need not be explicitly specified.
[Example:
void f(Array<dcomplex>& cv, Array<int>& ci)
{
sort(cv); // call sort(Array<dcomplex>)
sort(ci); // call sort(Array<int>)
}
and
void g(double d)
{
int i = convert<int>(d); // call convert<int,double>(double)
int c = convert<char>(d); // call convert<char,double>(double)
}
—end example]
如果可以从函数参数类型中推导出模板参数,则不用说明。
[root@Harry functemplate]# cat functemplate.cpp
template<class T>
int templ(T & t)
{
    return t + 1;
}
int templ(int &t)
{
    return t * t;
}
[root@Harry functemplate]# gcc -c functemplate.cpp
  评论这张
 
阅读(870)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017