6

嗯,在 VC2012 中是一个奇怪的问题,我似乎无法弄清楚通过 const 引用将 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
}

所以我在这里简化了我的问题,但基本上我希望“添加”的参数有一个 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 

我可以看到是正确的,但是如何在没有 const 将“名称”转换为非 const 的情况下解决它。

4

5 回答 5

9

There is a strong difference between a pointer to a constant object (T const*, or const T*) and a constant pointer to a non-constant object (T * const). In your case the signature of the member Add is:

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

I usually recommend that people drop the use of const on the left hand side exactly for this reason, as beginners usually confuse typedefs (or deduced types) with type substitution and when they read:

const T& [T == char*]

They misinterpret

const char*&

If the const is placed in the right place:

T const &

Things are simpler for beginners, as plain mental substitution works:

char * const &

A different problem than what you are asking, but maybe what you think you want, is:

Given a type T have a function that takes a U that is const T if T is not a pointer type, or X const * if T is a pointer to 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;
};

Then you can use this in your signature:

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

Note that I am adding two const in the signature, so in your case char* will map to char const * const &, as it seems that you want to pass a const& to something and you also want the pointed type to be const.

You might have wondered as of the name for the metafunction: *add_const_here_or_there*, it is like that for a reason: there is no simple way of describing what you are trying to do, which is usually a code smell. But here you have your solution.

于 2013-04-22T15:40:20.747 回答
3

看起来像您的问题,因为一旦您将指针类型映射到模板类型,您就不能再将 const-ness 添加到指向的类型,只能添加到指针本身。看起来您正在尝试做的是自动将 constness 添加到函数的参数中(因此,如果 T 是char*函数应该接受const char* const&而不是char* const&像您编写的那样)。做到这一点的唯一方法是使用另一个模板为指针类型的指针添加常量,如下所示。我冒昧地添加了丢失的标题并更正了以下签名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 风格的字符串,这个问题就会消失。

于 2013-04-22T16:40:30.463 回答
1

如果传递const char*而不是char*toFoo不是一个选项,您可以使用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::decay使用std::remove_pointer

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

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

于 2013-04-22T16:03:34.743 回答
1

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

于 2013-04-22T15:29:33.960 回答
1

利用:

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

int main()而不是void main()

于 2013-04-22T15:31:17.433 回答