Приведение класса шаблона с оператором T* при передаче в качестве аргумента T* шаблона функции

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

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 ответов

Решение

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));
}

Это немного многословно, хотя;-)

Это может стоить попробовать:

doStuff<Bar>(f);

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

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

doStuff(static_cast<Bar*>(f));

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

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


template 
inline
void 
doStuff(T& arrRef)
{
  doStuff(&arrRef);
}
Другие вопросы по тегам