2017-02-15 53 views
3

我有一個編譯器錯誤的問題,看看下面的代碼:編譯器會忽略「常量」的功能參數

template<class T> 
struct MyStruct 
{ 
}; 

template<> 
struct MyStruct<int> 
{ 
    typedef int* type; 
}; 

template<class T> 
void foo(const typename MyStruct<T>::type myType) 
{ 
} 

int main() 
{ 
    const int* ptr = NULL; 
    foo<int>(ptr); 

    return 0; 
} 

的問題是,編譯器無視於foo功能「常量」,使foo調用非法(const int * to int *)。

嚴重性代碼說明項目文件的線路抑制狀態 錯誤C2664 '無效美孚(常量MYSTRUCT ::類型)':不能轉換參數1 'const int的*' 到 '常量MYSTRUCT ::型'

我在Visual Studio和gcc的5.3編譯器中測試了以下代碼,它們都丟失了相同的錯誤。

編譯器是否故意這樣做?爲什麼發生這種情況?

+3

'const int * ptr'不是一個常量指針,它是一個指向const的指針。 – juanchopanza

回答

7

const int *int * const之間有一個重要的區別。請參閱this answer瞭解不同之處。

請考慮const typename MyStruct<T>::type的含義。這是一個MyStruct<T>::typeconst。在這種情況下,它是int*const。這是一個int* const,一個指針,不能重新分配一個新的地址,但仍然可以用來修改指出的int。但是,您傳遞的指針foo<int>(ptr)const int *,它不能轉換爲int * const,因爲它將丟棄const限定符。

爲了達到您想要的效果,const在成爲指針之前必須是類型的一部分。它不能在事後添加,或者總是被解釋爲T * const。您可以使用類型特徵來移除類型的指針部分,添加const然後使其成爲指針。

#include <type_traits> 

template<class T> 
struct MyStruct { }; 

template<> 
struct MyStruct<int> { 
    typedef int* type; 
}; 

template<class T> 
void foo(std::add_const_t<std::remove_pointer_t<typename MyStruct<T>::type>> * myType) {} 

int main() 
{ 
    const int* ptr = nullptr; 
    foo<int>(ptr); 

    return 0; 
}