C++ typename使用時機

C++ typename使用時機

前言

PCL中的surface/include/pcl/surface/mls.h裡宣告的pcl::MovingLeastSquares類別有這麼一段代碼:

using KdTree = pcl::search::Search<PointInT>;
//typename specifies that it is the name of a type
using KdTreePtr = typename KdTree::Ptr;
// 模板中的參數已經給定,是個具體的類型,所以不用加typename告知編譯器它是一個類別
using NormalCloud = pcl::PointCloud<pcl::Normal>;
using NormalCloudPtr = NormalCloud::Ptr;

using PointCloudOut = pcl::PointCloud<PointOutT>;
using PointCloudOutPtr = typename PointCloudOut::Ptr;
using PointCloudOutConstPtr = typename PointCloudOut::ConstPtr;

using PointCloudIn = pcl::PointCloud<PointInT>;
using PointCloudInPtr = typename PointCloudIn::Ptr;
using PointCloudInConstPtr = typename PointCloudIn::ConstPtr;

using SearchMethod = std::function<int (pcl::index_t, double, pcl::Indices &, std::vector<float> &)>;

觀察KdTreeKdTreePtr,可以發現一個沒加,另一個則有加typename。他們之間的區別詳見下文。

KdTreePtr

KdTree::Ptr簡化前為pcl::search::Search<PointInT>::Ptr,因為它具體是什麼要依賴於PointInT,在編譯時並不知道它是一個類別,所以在這裡加上typename讓編譯器知道。

參考C++ Cast Template,如果我們要調用castpcl::search::Search<PointInT>::Ptr做型別轉換,編譯器在不知道pcl::search::Search<PointInT>::Ptr是一個類型的情況下,可能會把cast當成它的成員變量,因而導致編譯錯誤。所以這裡加上typename讓編譯器知道它是一個類別後,就能成功編譯了。

KdTree

那麼為什麼KdTree不用加typename呢?參考Where and why do I have to put the “template” and “typename” keywords?

There are many names for which typename is not necessary, because the compiler can, with the applicable name lookup in the template definition, figure out how to parse a construct itself - for example with T *f;, when T is a type template parameter. But for t::x * f; to be a declaration, it must be written as typename t::x *f;.

我們可以用模板參數T直接去定義一個變量,但是如果想要用T::x定義一個變量卻是行不通的(編譯器會把x當作T類型的成員變量),必須要在T::x之前加上typename,讓編譯器知道它是一個類型才行。

The syntax allows typename only before qualified names - it is therefore taken as granted that unqualified names are always known to refer to types if they do so.

typename關鍵字只能加在qualified names(可以想成有帶::的類別名稱)之前,unqualified names總是會被當成類別名稱,所以不需要加typename關鍵字。

來看一下qualified name的定義,參考Qualified name lookup

A qualified name is a name that appears on the right hand side of the scope resolution operator :: (see also qualified identifiers). A qualified name may refer to a

    class member (including static and non-static functions, types, templates, etc)
    namespace member (including another namespace)
    enumerator 

它將qualified name的定義說得很明白,也就是::運算符後面的名稱。qualified name可以是一個類別的成員,命名空間的成員,或是enum。

在這邊的例子中,將模板參數PointT代入pcl::search::Search<PointInT>後,編譯器便可以很容易地知道它是一個類型(對照上面的T* f),所以不需要加typename

如果我們想用pcl::search::Search<PointInT>::Ptr定義一個變數,因為它是一個qualified name(對照上面的T::x* f),所以必須在它之前加上typename

範例程序

以下程序展示typename的使用時機:

#include <iostream>
#include <memory>

template<typename T>
class Animal{
public:
    using Ptr = std::shared_ptr< Animal< T > >;
};

template<typename T>
void f(){
    Animal<T> a;

    //error: need ‘typename’ before ‘Animal<T>::Ptr’ because ‘Animal<T>’ is a dependent scope
    //error: expected ‘;’ before ‘ap’
    //Animal<T>::Ptr ap;

    typename Animal<T>::Ptr ap;
}

int main(){
    Animal<int> a;
    Animal<int>::Ptr ap;
    return 0;
}

首先定義一個模板類別Animal,裡面有個成員Ptr

main函數中,因為我們給定了Animal的模板參數,所以編譯器知道他們兩個都代表一種類型,可以成功編譯。

f函數中,我們可以用Animal<T>定義一個變數a,但是卻無法用Animal<T>::Ptr去定義變數ap,必須在之前加上typename才行。這是因為在T不確定的情況下,編譯器把Ptr當成Animal<T>類別的成員變數而不把它視為一個類型,因此無法用它去定義其他變數。

以上程序放在typename_keyword.cpp

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值