2014-09-12 6 views
6

Рассмотрим следующий класс шаблона:C шаблон ++ с «сопзЬ»

template <typename T> class Function { 
public: 
    virtual float eval(const T &x, const T &y) = 0; 
}; 

Поскольку функция «Eval» не следует изменять значение «х» два входа и «у», я их как " Уст. Затем я создаю следующий класс, производный от функции

class Foo1 : public Function <float*> { 
public: 
    Foo1() : Function <float*>() {} 
    virtual float eval(const float* &x, const float* &y) { ... } 
}; 

Когда я компилирую с г ++, я получаю следующее предупреждение:

hidden overloaded virtual function 'Function<float *>::eval' declared here: type mismatch at 1st parameter 
     ('float *const &' vs 'const float *&') 
     virtual float eval(const T &x, const T &y) = 0; 

И я не могу создать экземпляр класса Foo1. Компилятор говорит, что функция eval не реализована. Для того, чтобы компилятор счастливым, производный класс должен выглядеть следующим образом:

class Foo2 : public Function <float*> { 
public: 
    Foo2() : Function <float*>() {} 
    virtual float eval(float* const &x, float* const &y) { ... } 
}; 

функция Foo2 :: Eval использует два параметра типа «флоат * сопзЬ» вместо «сопзЬ флоат *». Другими словами, Foo2 :: eval может изменять содержимое массивов «x» и «y». Это не то, что я хочу.

Я попытался изменить класс шаблона «Функция» следующим образом:

virtual float eval(T const &x, T const &y) = 0; 

Но класс Foo1 все еще не работает, класс Foo2 работает как и в предыдущем случае.

  1. Таким образом, кажется, что либо «сопзЬ T & х» или «T Const & х» в классе шаблона означает «поплавок * сопзИ & х» в производном классе. Это верно?
  2. Если я хочу 'const float * & x' (или 'const float * x') в производном классе, каким должен быть класс шаблона Function?

спасибо.

ответ

1

кажется, что либо const T &x или T const &x в классе шаблона подразумевает в производном классе float* const &x. Это верно?

Да, это правильно. Способ думать об этом заключается в том, что T всегда const; в вашем случае T оказывается указателем.

Если я хочу const float* &x (или const float* x) в производном классе, каким должен быть мой шаблон класса функции?

Похоже, что это должно быть class Foo2 : public Function <const float*>.

0

Выходом является частично специализировать Function для типов указателей, чтобы использовать различные подписи для eval:

template <typename T> class Function<T*> { 
    public: 
     virtual float eval(const T* x, const T* y) = 0; 
}; 

В качестве альтернативы, вы можете получить Foo2 от Function<const float*>.

8

Поведение, которое вы наблюдаете, на 100% правильное в плане стандарта. Это классический пример «постоянного указателя» против «указателя на константу».

Ваш основной шаблон заявляет, что берет «ссылку на T, через которую он не может изменять T объект именуются» (синтаксис const T &, что эквивалентно T const &).

Затем вы создаете шаблон с типом float*, то есть «указатель на float». Из этого следует, что тип параметра функции после замещения параметра шаблона действительно «ссылается на float *, через который он не может изменить начальную ссылку float *». Невозможно провести контрабанду: «Невозможно изменить float, на который прямо ссылаются« float * ».

Я вижу два варианта. Во-первых, если этот вид использования является единственным использование T в Function, просто использовать const float * в качестве аргумента шаблона, так как это T вы действительно хотите:

class Foo1 : public Function <const float*> { 
public: 
    Foo1() : Function <const float*>() {} 
    virtual float eval(const float* const &x, const float* const &y) { ... } 
    // notice two `const` keywords above: one for the pointed object, one for the reference 
}; 

Если это не вариант для вас (т.е. если вам нужно float * где-то внутри Function и const float* в другом месте), вам придется использовать некоторые свойства типа и изменить параметры eval. Что-то вроде этого:

template <class T> 
struct unmodifiable { 
    typedef const T &type; 
}; 

template <class T> 
struct unmodifiable<T*> { 
    typedef const T* const &type; // if you want to keep the reference 
    // or just: 
    // typedef const T *type; // if you don't want to bother with the reference for pointer types 
}; 

template <typename T> class Function { 
public: 
    virtual float eval(typename unmodifiable<T>::type x, typename unmodifiable<T>::type y) = 0; 
}; 

class Foo1 : public Function <float*> { 
public: 
    Foo1() : Function <float*>() {} 
    virtual float eval(unmodifiable<float*>::type x, unmodifiable<float*>::type y) { ... } 
    // or just spell it out exactly, based on the variant of `unmodifiable` you've chosen, e.g.: 
    // virtual float eval (const float *x, const float *y) { ... } 
}; 
Смежные вопросы