Приведение класса шаблона с оператором T * при передаче в качестве аргумента T * шаблона функции - PullRequest
0 голосов
/ 13 октября 2008

Предположим, у меня есть такой шаблон функции:

template<class T>
inline
void
doStuff(T* arr)
{
  // stuff that needs to use sizeof(T)
}

Затем в другом .h файле у меня есть шаблон класса Foo, который имеет:

public: operator T*() const;

Теперь я понимаю, что это разные Ц. Но если у меня есть переменная Foo<Bar> f в стеке, единственный способ привести ее к любому указателю - вызвать operator T*(). Тем не менее, если вызов doStuff(f), GCC жалуется, что doStuff не может принять Foo<Bar> вместо автоматического использования оператора T*() для принудительного обращения к Bar*, а затем специализировать шаблон функции с Bar как T.

Могу ли я что-нибудь сделать, чтобы эта работа работала с двумя шаблонами? Или аргумент функции шаблона должен быть реальным типом указателя, или класс шаблона с оператором приведения должен быть передан в не шаблонную функцию?

Ответы [ 5 ]

3 голосов
/ 13 октября 2008

GCC правильно. В аргументах шаблона учитываются только точные совпадения, а преобразования типов - нет. Это связано с тем, что в противном случае необходимо учитывать бесконечное (или, по крайней мере, экспоненциальное) количество конверсий.

Если Foo является единственным другим шаблоном, к которому вы собираетесь запускать, лучшим решением будет добавить:

template<typename T> inline void doStuff(const Foo<T>& arr) {
    doStuff(static_cast<T*>(arr));
}

Если у вас возникла эта проблема с большим количеством шаблонов, этот должен исправить ее:

#include <boost/type_traits/is_convertible.hpp>
#include <boost/utility/enable_if.hpp>
template<template <typename> class T, typename U> inline typename boost::enable_if<typename boost::is_convertible<T<U>, U*>::type>::type doStuff(const T<U>& arr) {
    doStuff(static_cast<U*>(arr));
}

Хотя это немного многословно; -)

2 голосов
/ 13 октября 2008

Возможно, стоит попробовать:

doStuff<Bar>(f);

Я думаю, это заставит компилятор ожидать, что T * будет Bar *, а затем использовать оператор Foo T * () для выполнения приведения, но я не могу сказать, что пробовал.

0 голосов
/ 13 октября 2008

Идея Леона, вероятно, лучшая. Но в крайнем случае вы могли бы также явно вызвать оператор приведения:

doStuff(static_cast<Bar*>(f));
0 голосов
/ 13 октября 2008

Ну, T * не является отдельным типом от T в том смысле, в каком вы думаете. Указатель является классификатором типа. Я не уверен, что стандарт говорит об этом, но я бы сказал, что, поскольку переменная уже имеет тип T, она не пытается преобразовать снова. Если вы хотите сделать что-то нестандартное для получения указателя, перегрузите оператор &.

0 голосов
/ 13 октября 2008

Я не уверен, почему преобразование не работает, но вы можете использовать перегрузку, чтобы решить проблему


template 
inline
void 
doStuff(T& arrRef)
{
  doStuff(&arrRef);
}
...