передача шаблона по константной ссылке - PullRequest
1 голос
/ 02 февраля 2011

Я просмотрел несколько похожих вопросов, но все еще в замешательстве. Я пытаюсь выяснить, как явно (не с помощью оптимизации компилятора и т. Д.) И C ++ 03-совместимого избежать копирования объекта при передаче его в специализированную шаблонную функцию. Вот мой тестовый код:

#include <iostream>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void f(T) { cout << "f<T>" << endl; }

// This shows two possible ways, I don't need two overloads
// If I do it like (2) the function is not called, only if I do it like (1)

template<> void f(C c) { cout << "f<C>" << endl; } // (1)

template<> void f(const C& c) { cout << "f<C&>" << endl; } // (2)

int main()
{
    C c;
    f(c);
    return 0;
}

(1) принимает объект типа C и создает копию. Вот вывод:

C()
C(C)
f<C>
~C()
~C()

Поэтому я попытался специализироваться с параметром const C& (2), чтобы избежать этого, но это просто не работает (очевидно, причина объяснена в этом вопросе ).

Ну, я мог бы "пройти по указателю", но это некрасиво. Так есть ли какой-нибудь трюк, который позволил бы сделать это как-нибудь красиво?

РЕДАКТИРОВАТЬ: О, вероятно, я не был ясен. У меня уже есть шаблонная функция

template<class T> void f(T) {...}

Но теперь я хочу специализировать эту функцию, чтобы принимать const & для другого объекта:

template<> void f(const SpecificObject&) {...}

Но он вызывается только если я определю его как

template<> void f(SpecificObject) {...}

В основном я хочу адаптировать SpecificObject к интерфейсу шаблона, например

.
template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version

EDIT2: Хорошо, я могу заставить специализацию const C& вызывать так:

f<const C&>(c);

но есть ли способ заставить его работать так, как просто f(c)?

РЕДАКТИРОВАТЬ3: Если у кого-то в конечном итоге возникнут подобные вопросы, я наконец нашел эту ссылку в другом вопросе, и это полезно: http://www.gotw.ca/publications/mill17.htm

Ответы [ 6 ]

3 голосов
/ 02 февраля 2011

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

Просто удалите специализации и передайте аргумент как T const&.

Приветствия и hth.,

2 голосов
/ 02 февраля 2011

Это будет работать:

int main()
{
    C c;
    f<const C&>(c);
    return 0;
}

Ваша альтернатива:

template<typename T> void f(const boost::reference_wrapper<T const>& c) 
    { cout << "f<boost_const_ref&>" << endl; } 

int main()
{
    C c;
    f(boost::cref(c));
    return 0;
}

В действительности вы бы использовали boost :: reference_wrapper для передачи ссылки туда, где вы хотите ее использовать.Для этого вы можете использовать get (), хотя boost :: reference_wrapper имеет неявное преобразование обратно в ссылку, так что вы можете обойтись без частичной специализации шаблона и просто передав boost::cref(c) обычному.

2 голосов
/ 02 февраля 2011

Почему бы вам не перегрузить:

void f(const C& c) { cout << "f(const C&)" << endl; }
1 голос
/ 03 февраля 2011

Ваша проблема в том, что фактический параметр c не является const, поэтому основной шаблон лучше подходит, потому что ему не нужно добавлять 'const' к типу.Если вы попробуете функции, которые передаются по значению и по неконстантной ссылке, компилятор скажет вам, что он не может устранить эту разницу.

1 голос
/ 02 февраля 2011

Так что, если вы не всегда хотите принимать константную ссылку (что целесообразно для базовых типов [int, long, float и т. Д.]), Вы можете использовать немного магии повышения.

#include <iostream>
#include <boost/call_traits.hpp>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  //C& operator=(C const&) { cout << "C=C" << endl; return *this; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void foo(typename boost::call_traits<T>::param_type inst) { cout << "f<T>" << endl; }
// specialization for calling class C
template<> void foo<C>(boost::call_traits<C>::param_type inst) { cout << "f<C>" << endl; }

int main()
{
  int i = 0;
  foo<int>(i);
  C c;
  foo<C>(c);
  return 0;
}
0 голосов
/ 02 февраля 2011
#include <iostream>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void f(const T&) { cout << "f<T>" << endl; }

int main()
{
    C c;
    f(c);
    return 0;
}

Это делает то, что вы хотите, но вы должны затем использовать const ref для всех значений, переданных в функцию. Я не знаю, было ли это то, что вы искали.

...