在模板函数参数列表中忽略Const

时间:2018-04-27 18:59:31

标签: c++ templates pointers visual-c++

我在模板类中遇到函数定义问题。

我有一个模板类Array,它有一个成员函数IndexOf

// Defined in header
template <typename T>
class Array {
    // Other stuff

    int IndexOf(const T value) const {
        // Code of function
    };

    // Other stuff
};

当我使用类指针创建数组实例时,函数忽略 const T并使用T。因此,当我使用const T调用该函数时,会出现编译器错误:“没有重载函数的实例”:

#include "Array.h"

class Object{
    // Object stuff
};

int main(){
    // Demonstration code
    Array<Object*> objects = Array<Object*>(); // Array of Object*
    Object* obj = new Object();                // An Object*
    const Object* cobj = new Object();         // A const Object*

    // This works fine
    objects.IndexOf(obj); // No problems

    // This has compile error
    objects.IndexOf(cobj); // No idea why

    delete obj;
    delete cobj;

    return 0;
}

代码似乎忘记函数的参数是const T。函数参数应为const Object*,但它将参数视为仅Object*

知道为什么会这样吗?

如果我没有使用指针作为类型,则不会发生错误。

函数内的代码不会导致问题。

在说出之前,不,我不会使用std::vector或类似的其他人来拥有动态调整大小的数组。这可以带来所有的乐趣。

3 个答案:

答案 0 :(得分:2)

实际上,您对该功能的声明可以被视为:

 IndexOf(const (Object *) val)

这基本上意味着Object *应该指向const对象:

 Object *const cobj = new Object();

现在你将有正确的行为。 但是,如果您对const指针感兴趣,那么您需要将声明修改为:

  Array<const Object *> objects;

答案 1 :(得分:0)

<const T value T Object* Object* const valueconstconst T value中的value适用于T,不会修改const T valuevalue是类型T的{​​{1}},无法更改,指针无法为其分配新地址。很明显,使用const Object *无法调用以下函数。

int IndexOf(Object * const value) const // const pointer to non-const Object

要将const添加到指向类型,可以使用type-traits获取指向类型,向其添加const,然后从中生成新的指针类型。例如:

#include <type_traits>

template<class T>
using add_const_to_ptr =
    std::add_pointer_t<
    std::add_const_t<
    std::remove_pointer_t<T>>>;

其用法如下:

template<class T>
struct container {
    void push(add_const_to_ptr<T> ptr) {
        (void)ptr;
    }
};

struct bar {};

int main()
{
    const bar cbar;
    bar mbar;

    container<bar*> my_container;

    my_container.push(&mbar);
    my_container.push(&cbar);
}

虽然这假定container只会与指针一起使用,但在这种情况下,使T引用指向的对象类型而不是指针类型可能更好。如果T可能是也可能不是指针类型,则可以通过检查T实际上是否为std::conditional的指针来改进类型特征:

#include <type_traits>
template<class T>
using add_const_to_ptr =
std::conditional_t<std::is_pointer<T>::value,
    std::add_pointer_t<
    std::add_const_t<
    std::remove_pointer_t<T>>>,
    T>;

答案 2 :(得分:0)

您可以将Array<Object*>::IndexOf()声明为模板:

template <typename U>
int IndexOf(const U& value) const {
    // Code of function
}

并在里面将value与数组的内容进行比较,该比较会将内容从Object*转换为const Object*,这当然是允许的。

使用这种方法,您可以将T可以转换为/的任何内容传递给该函数。