2017-02-15 52 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; 
}