C ++通过const引用传递一个const指针

时间:2013-04-22 15:22:04

标签: c++ const

在VC2012中我是一个奇怪的人我似乎无法解决将const指针通过const引用传递给模板化类的函数的语法,模板化参数是非常量指针,即:

template<typename T>
struct Foo
{
    void Add( const T& Bar ) { printf(Bar); }
};

void main()
{
Foo<char*> foo;
const char* name = "FooBar"; 
foo.Add(name);                 // Causes error
}

所以我在这里简化了我的问题,但基本上我希望'Add'的参数有一个const T即const char *。我试过了:

void Add( const (const T)& Bar ); 

typedef const T ConstT;
void Add( const (ConstT)& Bar );  

void Add( const typename std::add_const<T>::type& Bar ); 

这些都不起作用。我得到的确切错误是:

error C2664: 'Foo<T>::Add' : cannot convert parameter 1 from 'const char *' to 'char *const &'
          with
          [
              T=char *
          ]
          Conversion loses qualifiers 
我能看到的

是正确的,但是如果不将常量'name'变为非const,我该如何解决它。

5 个答案:

答案 0 :(得分:7)

指向常量对象(T const*const T*)的指针与指向非常量对象(T * const)的常量指针之间存在很大差异。在您的情况下,成员Add的签名是:

void Foo<char *>::Add(char * const& ); // reference to a constant pointer to a 
                                       // non-constant char

我通常建议人们完全放弃在左侧使用const,因为初学者通常会将typedef(或推断类型)与类型替换混淆,当他们阅读时:

const T& [T == char*]

他们误解了

const char*&

如果const位于右侧位置:

T const &

初学者的事情比较简单,因为简单的心理替代是有效的:

char * const &

与您提出的问题不同,但也许您认为自己想要的问题是:

如果T类型U不是指针类型,则const T类型的函数需要T X const *T如果X是指向template <typename T> struct add_const_here_or_there { typedef T const type; }; template <typename T> struct add_const_here_or_there<T*> { typedef T const * type; };

的指针
template <typename T>
void Foo<T>::Add( const typename add_const_here_or_there<T>::type & arg ) {
     ...

然后你可以在你的签名中使用它:

const

请注意,我在签名中添加了两个char*,因此在您的情况下char const * const &会映射到const&,因为您似乎想要传递const某事,你也希望指向的类型为{{1}}。

你可能想知道元函数的名称:* add_const_here_or_there *,它就是这样的原因:没有简单的方法来描述你想要做什么,这通常是代码味道。但是你有解决方案。

答案 1 :(得分:2)

看起来你的问题是,只要你有一个映射到模板类型的指针类型,你就不能再将指针添加到指向类型,只能指向指针本身。你试图做的是自动添加constness到你的函数的参数(所以如果T是char*,函数应该接受const char* const&而不是char* const&,因为你已经书面)。唯一的方法是使用另一个模板将constness添加到指针类型的指针,如下所示。我冒昧地包含了丢失的标题并更正了main的签名:

#include <cstdio>

template<typename T>
struct add_const_to_pointee
{
    typedef T type;
};

template <typename T>
struct add_const_to_pointee<T*>
{
    typedef const T* type;
};

template<typename T>
struct Foo
{
    void Add( typename add_const_to_pointee<T>::type const & Bar ) { printf(Bar); }
};

int main()
{
    Foo<char*> foo;
    const char* name = "FooBar";
    foo.Add(name);                 // Causes error
}

正如另一个人所提到的,如果您使用std::string而不是C风格的字符串,这个问题就会消失。

答案 2 :(得分:1)

您需要将Foo对象的模板参数更改为Foo<const char*>。因为如果T=char*,则为const T=char*const,而不是const char*。试图强迫它发挥作用并不是一个好主意,可能会导致未定义的行为。

答案 3 :(得分:1)

使用:

Foo<const char*> foo;
const char* name = "FooBar"; 
foo.Add(name);     

并写下int main()而不是void main()

答案 4 :(得分:1)

如果无法将const char*而不是char*传递给Foo,则可以使用std::remove_pointer精确打印正确的类型。这将删除指针修饰符,并允许您提供更明确的类型。

#include <type_traits>

template<typename T>
struct Foo
{
    void Add(typename std::remove_pointer<T>::type const*& Bar ) { printf(Bar); }
};

为了防止修改指针值,您也可以将引用声明为const

void Add(typename std::remove_pointer<T>::type const* const& Bar )
{ Bar = "name"; } // <- fails

如果您需要将类型从指针指向,请将std::decaystd::remove_pointer一起使用

void Add(typename std::remove_pointer<typename std::decay<T>::type>::type const*& Bar)
{
    printf(Bar);
}

这实际上取决于您对T的要求。我建议假设只将基类型(例如char)作为T传递,并从中构建引用和指针类型。

相关问题