Здравствуйте, rpz, Вы писали:
rpz>Но остается вопрос зачем вообще тогда Александреску вводит такой тип у TypeTraits? По идее то он сделан для того чтобы можно было определить тип параметра и соответственно или оставить ссылку или оставить по значению или сделать константную ссылку. А получается что так его использовать нельзя. Или все же можно как-то?
Во-первых, есть такая функция — "идентичность". id(x)=x. Может пригодиться, когда мы используем её как параметр другой функции:
// функции над данными
int id(int x) { return x; }
int succ(int x) { return x+1; }
int pred(int x) { return x-1; }
void foo(int(*f)(int)) { std::cout << f(123) << std::endl; }
// функции над типами
template<class T> struct Id { typedef T type; };
template<class T> struct AddStar { typedef T* type; };
template<class T> struct RemoveStar { typedef T type; };
template<class T> struct RemoveStar<T*> { typedef T type; };
template< template<class> class Fun > void Foo()
{
std::cout << typeid( typename Fun<int***>::type ).name() << std::endl;
}
int main()
{
foo(id); foo(succ); foo(pred);
Foo<Id>(); Foo<AddStar>(); Foo<RemoveStar>();
}
Во-вторых, мы можем передать в шаблон не сам тип, а его характеристику (traits). И шаблон оттуда извлечёт всё, что ему нужно, в том числе исходный тип.
template<class TT> struct Foo
{
typedef TT::ParameterType TheType;
.....
};
В-третьих, для нескольких разных типов будет одинаковый ParameterType. Особенно Александреску любил находить "наиболее подходящий способ передачи параметров". Для примитивных типов выгоднее передавать их в функцию по значению: foo(int). Для громоздких типов — по константной ссылке: foo(const std::string). Для неконстантных ссылок — как есть: foo(int&).
Так что TypeTraits<std::string>::ParameterType может быть const std::string&.
На самом деле, как показала практика, Александреску здесь подложил грабли с длинными гвоздями, запутанными в траве. И уже в boost::bind / boost::function отказались от "хитроумной" передачи параметров, предпочитая всегда по значению, либо явно указывая способ передачи.