2015-04-14 4 views
2

я узнал, что вы можете специализироваться для динамически выделенных массивов с T[]:Правильно вперед специализации для динамически выделенных массивов

template<typename T> 
class C {}; 

template<typename T> 
class C<T[]> {}; 

Теперь при попытке использовать такую ​​технику, мне кажется, есть проблема, сочиняет эту функцию (с помощью его во внутреннем слое, например, внутри шаблона функции):

#include <iostream> 

template<class _Ty> 
struct OP 
{ 
    void operator()(_Ty *_Ptr) const noexcept 
    { 
     std::cout << "single pointer\n"; 
     delete _Ptr; 
    } 
}; 

template<class _Ty> 
struct OP<_Ty[]> 
{ 
    void operator()(_Ty *_Ptr) const noexcept 
    { 
     std::cout << "dynamically allocated array\n"; 
     delete[] _Ptr; 
    } 
}; 

template<typename T> 
void f1(T *arg) 
{ 
    OP<T>()(arg); 
} 


int main() 
{ 
    f1(new int(3)); 
    f1(new int[(3)]); 
} 

The above отпечатки

одного указателя

одного указателя

, когда становится ясно, что второй вызов делается с массивом. Как я могу это исправить, что я делаю неправильно?

+3

'f1' принимает указатель. Затухание от массива к указателю происходит, и результирующим экземпляром для функции является 'f1 (int *)' для обоих вызовов, где 'T = int'. Поэтому выбрана специализация 'OP '. – 0x499602D2

+0

@ 0x499602D2 Мне нужно отправить внутри функции. Могу ли я изменить подпись функции, чтобы сделать эту работу? –

+0

К сожалению. В моем последнем комментариях размытие между массивами и указателями * не произошло *, оператор 'new' всегда возвращает указатель на выделенную память. В любом случае, способ исправить это будет состоять в том, чтобы передать тип явно как аргумент шаблона и заставить операторы вашего вызова разложившиеся версии типов (http://coliru.stacked-crooked.com/a/84ad65025dacd8cd). Кроме того, не начинайте идентификаторы с подчеркиванием. – 0x499602D2

ответ

3

Оба ваших звонка одного типа. Мы можем проверить это с простой программой:

int main() 
{ 
    static_assert(std::is_same< 
     decltype(new int(3)), 
     decltype(new int[(3)]) 
    >{}, "wat"); 
} 

Это отмечается в стандарте в [expr.new]:

Когда выделенный объект является массивом (то есть, noptr новый синтаксис -declarator или идентификатор типа new-type или обозначает тип массива), новое выражение дает указатель на исходный элемент (если он есть) массива. [Примечание: как new int и new int[10] имеют тип int* и типа new int[i][10] является int (*)[10] -end примечания] Атрибут спецификатор-сл через noptr-новый описатель appertains к соответствующему типу массива.

Таким образом, нет никакого способа отличить указатель на один элемент из указателя на массив по его типу. Вы могли бы пройти в какой-то дополнительный тег, хотя, как:

struct array_tag { }; 
struct single_tag { }; 

f1(new int(3), single_tag{}); 
f1(new int[3], array_tag{}); 

Или просто явно указать типы (это потребует изменения несколько других подписей - f1 бы взять T, не T* и т.д.):

f1(new int(3)); 
f1<int*>(new int(3)); 

f1<int[]>(new int[3]); 
Смежные вопросы