提出问题:

如果有这样一个模板:

template <typename T> class Test{
public:
static std::string info;
};

  对于以下若干种定义方式,哪些是对的(通过编译)?

template <> string Test<int>::info("123");
template <typename T> string Test<T>::info("123");
template <typename T> string Test<T>::info;
template <> string Test<int>::info;
template <> string Test<int>::info();
template <typename T> string Test<T>::info();

  为了不影响大家分析判断,我把答案颜色调成比较浅的颜色,下面即是答案:

  1. template <> string Test<int>::info("123");//ok
  2. template <typename T> string Test<T>::info("123");//ok
  3. template <typename T> string Test<T>::info;//ok
  4. template <> string Test<int>::info; //error
  5. template <> string Test<int>::info();//error
  6. template <typename T> string Test<T>::info();//error

问题解答:

首先,说明一下三个正确的答案。

第一种形式称之为特化定义,其作用是为模板某一特化提供其静态成员的定义,在我们例子中,它仅仅为Test<int>类的静态成员info提供定义。并且调用单参数构造函数初始化。

第 二种形式类似于普通类的静态成员的定义方式,其作用是隐式地在该编译单元为模板的所有特化提供其静态成员的定义,在我们例子中,在首次使用 Test<int>,Test<float>,Test<char>...会隐式提供静态成员的定义,并且调用单参 数构造函数初始化。

第三种形式和第二种形式一致,唯一不同就是采用默认构造函数初始化。

其次,说明一下三个错误的答案。

第一种形式,很多人都会认为是对的,认为它采用默认构造函数初始化。但编译器会对特化定义进行特殊处理,编译认为它是一个声明而非定义。至于为什么如此,应该询问一下制定标准的人。我认为可能实现这样的语法可能比较困难并且这个语法也比较鸡肋。

第二种形式,这不成了声明一个函数啦。

第三种形式,同第二种。

更多内容:

两种正确的定义方式还有哪些其他的区别呢?

//a.cpp
template <typename T> string Test<T>::info("4321");
可以使用Test<int>::info
//b.cpp
template <typename T> string Test<T>::info("1234");
也可以使用Test<int>::info

  这两个定义可以在不同的编译单元共存,Test<int>::info的初始值是多少,这取决与静态成员的初始化顺序,所以这不是件好事。

//a.cpp
template <> string Test<int>::info("123");
//b.cpp
template <> string Test<int>::info("123");

  而特化定义,上述方式无法通过编译。

//a.cpp
template <> string Test<int>::info("123"); //b.cpp
template <typename T> string Test<T>::info("123"); 一旦使用Test<int>::info无法通编译

  

上述方式无法通过编译。

一般为了避免无法编译,应当尽量减少使用,如下方式的定义

template <typename T> string Test<T>::info;

只有在你首次需要使用时在实现文件中给出如下特化定义即可,其他文件只要包含头文件就能使用。

template <> string Test<int>::info("123");

应用案例:

/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ #ifndef ANDROID_UTILS_SINGLETON_H
#define ANDROID_UTILS_SINGLETON_H #include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
#include <cutils/compiler.h> namespace android {
// --------------------------------------------------------------------------- template <typename TYPE>
class ANDROID_API Singleton
{
public:
static TYPE& getInstance() {
Mutex::Autolock _l(sLock);
TYPE* instance = sInstance;
if (instance == 0) {
instance = new TYPE();
sInstance = instance;
}
return *instance;
} static bool hasInstance() {
Mutex::Autolock _l(sLock);
return sInstance != 0;
} protected:
~Singleton() { };
Singleton() { }; private:
//禁止复制构造函数和赋值运算符函数,禁止类外部和内部以及友元调用 declare private,not define
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
static Mutex sLock;
static TYPE* sInstance;
}; /*
* use ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) in your implementation file
* (eg: <TYPE>.cpp) to create the static instance of Singleton<>'s attributes,
* and avoid to have a copy of them in each compilation units Singleton<TYPE>
* is used.
*
* NOTE: we use a version of Mutex ctor that takes a parameter, because
* for some unknown reason using the default ctor doesn't emit the variable! 特化定义必须使用有参数的构造函数,否则认为是声明!
*/
//想要使用Singleton,需要在自定义类型的实现文件中包含此宏,用以初始化类模版static变量,并显示实例化类模版
#define ANDROID_SINGLETON_STATIC_INSTANCE(TYPE) \
template<> Mutex Singleton< TYPE >::sLock(Mutex::PRIVATE); \ 特化定义
template<> TYPE* Singleton< TYPE >::sInstance(0); \ 特化定义
template class Singleton< TYPE >; \显示实例化 // ---------------------------------------------------------------------------
}; // namespace android

  

[转]C++ 模板 静态成员 定义(实例化)的更多相关文章

  1. C++模板 静态成员 定义(实例化)

    问一个问题: 考虑一个模板: template <typename T> class Test{ public: static std::string info; }; 对于下面若干种定义 ...

  2. C++ Primer 学习笔记_77_模板与泛型编程 --实例化

    模板与泛型编程 --实例化 引言: 模板是一个蓝图,它本身不是类或函数.编译器使用模板产生指定的类或函数的特定版本号.产生模板的特定类型实例的过程称为实例化. 模板在使用时将进行实例化,类模板在引用实 ...

  3. 读书笔记 effective c++ Item 46 如果想进行类型转换,在模板内部定义非成员函数

    1. 问题的引入——将operator*模板化 Item 24中解释了为什么对于所有参数的隐式类型转换,只有非成员函数是合格的,并且使用了一个为Rational 类创建的operator*函数作为实例 ...

  4. C++模板显式实例化,隐式实例化,特化(具体化,偏特化)辨析

    最近再次看C++ PRIMER PLUS的时候看到这个部分感觉讲得很烂,前后口径不一致,所以写个辨析让自己明白的同时也希望对此不太清楚的朋友能搞懂. 总结一下,C++只有模板显式实例化(explici ...

  5. C++ 模板的编译 以及 类模板内部的实例化

    在C++中.编译器在看到模板的定义的时候.并不马上产生代码,仅仅有在看到用到模板时,比方调用了模板函数 或者 定义了类模板的 对象的时候.编译器才产生特定类型的代码. 一般而言,在调用函数的时候,仅仅 ...

  6. c/c++模板的定义和实现分开的问题及其解决方案

    注意c/c++模板的定义和实现- -                                       定义一个类一般都是在头文件中进行类声明,在cpp文件中实现,但使用模板时应注意目前的C ...

  7. Ext.net Calendar 控件在有模板页的时候,模板页定义了TD的样式造成日历控件的样式丢掉

    Ext.net Calendar 控件在有模板页的时候,模板页定义了TD的样式造成日历控件的样式丢掉 解决方案 在本页面添加下面的样式 <style type="text/css&qu ...

  8. template <typename T>模板类定义

    #include "stdafx.h"#include "iostream"#include <ctime>using namespace std; ...

  9. c++模板使用及实现模板声明定义的分离

    c++模板是编译器构造具体实例类型的模型,使类型参数化,是泛型编程的基础,泛型就是独立于特定类型. 一.模板分为函数模板和类模板两种. 函数模板:template <class 形参名,clas ...

随机推荐

  1. java使用poi操作word, 支持动态的行(一个占位符插入多条)和表格中动态行, 支持图片

    依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifa ...

  2. Vue、SPA实现登陆

    axios/qs/vue-axios安装及使用步骤 首先我们要下载三个依赖包,方便后面的开发使用需要: npm install axios -S   axios是vue2提倡使用的轻量版的ajax.它 ...

  3. Hystrix 用法及注解用法

    一.hystrix参数使用方法 通过注解@HystrixCommand的commandProperties去配置,如下就是hystrix命令超时时间命令执行超时时间,为1000ms和执行是不启用超时 ...

  4. shell 学习笔记2-shell-test

    一.字符串测试表达式 前面一篇介绍:什么是shell,shell变量请参考: shell 学习笔记1-什么是shell,shell变量 1.字符串测试表达式参数 字符串需要用""引 ...

  5. c#使用GDI进行简单的绘图

    https://www.2cto.com/database/201805/749421.html https://zhidao.baidu.com/question/107832895.html pr ...

  6. windows + Eclipse

    https://www.eclipse.org/downloads/index-packages.php 下载好后是一个压缩文件,解压并放到相要存放软件的目录,双击打开解压后的目录下eclipse.e ...

  7. iOS - UIWebView和WKWebView的比较和选择-作为H5容器的一些探究

    一.Native开发中为什么需要H5容器 Native开发原生应用是手机操作系统厂商(目前主要是苹果的iOS和google的Android)对外界提供的标准化的开发模式,他们对于native开发提供了 ...

  8. element-ui默认样式修改

    来自 :https://blog.csdn.net/wangguoyu1996/article/details/81394707 侵删 我们在使用element-ui的时候经常会遇到需要修改组件默认样 ...

  9. Redis系列之-—内存淘汰策略(笔记)

    一.Redis ---获取设置的Redis能使用的最大内存大小 []> config get maxmemory ) "maxmemory" ) " --获取当前内 ...

  10. kubbernetes Flannel网络部署(五)

    一.Flannel生成证书 1.创建Flannel生成证书的文件 [root@linux-node1 ~]# vim flanneld-csr.json { "CN": " ...