2010-05-23 2 views
2

Я пытаюсь создать набор перегруженных шаблонов для массивов/указателей, где один шаблон будет использоваться, когда компилятор знает размер массива, а другой шаблон будет использоваться, т:могут ли эти шаблоны быть однозначными

template <typename T, size_t SZ> 
void moo(T (&arr)[SZ]) 
{ ... } 

template <typename T> 
void moo(T *ptr) 
{ ... } 

проблема заключается в том, что, когда компилятор знает размер массива, то перегруженные неоднозначны и компиляция терпит неудачу.

Есть ли способ устранить двусмысленность (возможно, через SFINAE), или это просто невозможно.

+0

Если не вторая перегрузка имеет 'size_t' параметра или что-то, так что функция будет знать размер массива, на который указывает 'ptr'? –

+0

Версия указателя необязательно должна быть для динамических массивов. @ins –

+0

Хороший вопрос, я наткнулся на ту же самую проблему. Для записи двусмысленность возникает из-за того, что преобразование матрицы в указатель считается точным совпадением во время разрешения перегрузки (§13.3.3.1.1). Я не считаю это очень интуитивным поведением, и мне было бы интересно узнать, почему такое решение было принято. –

ответ

5

Вполне возможно, так как это может быть определено параметром погода шаблона представляет собой массив или нет:

template<class T> struct is_array { 
    enum { value = false }; 
}; 
template<class T, size_t N> struct is_array<T[N]> { 
    enum { value = true }; 
}; 
template<class T> void f(T const&) { 
    std::cout << is_array<T>::value << std::endl; 
} 

Объединение, что с enable_if, выше, может быть сделано однозначным. Например, используя Boost.TypeTraits:

template <typename T, size_t SZ> 
typename boost::enable_if<boost::is_array<T>, void>::type 
f(T (&arr)[SZ]) {} 

Со ссылками однако нет никакой необходимости SFINAE вообще:

template<class T, size_t SZ> void f(T (&arr)[SZ]) {} 
template<class T>   void f(T* const& t) {} 

Йоханнес поднимает еще один вариант, который соответствует ситуации под рукой лучше - с помощью SFINAE для проблематичная перегрузка указателя вместо:

template <typename T, size_t SZ> void f(T (&arr)[SZ]) {} 
template <typename T> 
typename boost::enable_if<boost::is_pointer<T>, void>::type 
f(T ptr) {} 
+1

Если вы измените вторую функцию на 'T * const & t', вы даже можете принять выражения указателя rvalue. Чтобы показать, как он будет использовать ваш шаблон в сценарии * his *: 'template void f (T (& arr) [SZ]) {} template typename disable_if < is_array> :: type void f (T const & t) {} '. В конечном счете, я бы использовал 'is_pointer', чтобы сделать это с помощью' enable_if', потому что это привязка массива к 'T *', что делает проблему, а не привязку указателя к 'T [N]' (которая не будет работать). –

+0

@Johannes: Наверное, я склонен игнорировать значения, пока они не ударят меня. Как обычно, спасибо за вход :) –

0

Вы можете вызвать функцию в явном виде:

int a[1] = {0} 
moo<int,1>(a); 

Или вы можете перегрузить на ПОСТОЯННОМ:

template<class T> 
void moo(T const* p) { } 

// ... 
moo(a); // not const, array 

int* p = 0; 
moo(p); // pointer 
2

и, вероятно, самое простое решение:

template <typename T, size_t SZ> 
void moo(T (&arr)[SZ]) 
{ ... } 

template <typename T> 
inline void moo(T ptr) { __moo(ptr); } 

template <typename T> 
void __moo(T* ptr) 
{ ... } 
Смежные вопросы