По умолчанию для параметра шаблона используется более поздний

Эта ссылка не отвечает на мой вопрос, поэтому я задам его здесь:

В основном я хочу написать шаблонную функцию

template <typename Out, typename In>
Out f(In x);

Здесь мне всегда нужно указывать Out при звонке f, Я не хочу делать это каждый раз, поэтому я в основном хочу

template <typename Out = In, typename In>
Out f(In x);

Что означает, если я не укажу Out, по умолчанию In, Однако это невозможно в C ++ 11.

Итак, мой вопрос, есть ли способ добиться эффекта:

  1. призвание f(t) будет создавать f<T,T>(t) или в более общем плане f<typename SomeThing<T>::type, T>
  2. призвание f<U>(t) будет создавать f<U, T>(t)

5

Решение

Вы, вероятно, никогда не хотите указывать In а скорее вывели это, верно?

В этом случае вам необходимо перегрузить функцию:

template <typename Out, In>
Out f(In x);

template <typename T>
T f(T x);

Назови это:

f(42);
f<float>(42);

… но, к сожалению, это неоднозначно для f<int>(42), Неважно, мы можем использовать SFINAE, чтобы соответствующим образом отключить одну из перегрузок:

template <
typename Out,
typename In,
typename = typename std::enable_if<not std::is_same<Out, In>::value>::type
>
Out f(In x);

template <typename T>
T f(T x);

Чтобы избежать избыточности в реализации, пусть обе функции отправляются в общую реализацию, f_impl,

Вот рабочий пример:

template <typename Out, typename In>
Out f_impl(In x) {
std::cout << "f<" << typeid(Out).name() <<
", " << typeid(In).name() <<
">(" << x << ")\n";
return x;
}

template <
typename Out,
typename In,
typename = typename std::enable_if<not std::is_same<Out, In>::value>::type
>
Out f(In x) {
std::cout << "f<Out, In>(x):\t ";
return f_impl<Out, In>(x);
}

template <typename T>
T f(T x) {
std::cout << "f<T>(x):\t ";
return f_impl<T, T>(x);
}int main() {
f(42);
f<float>(42);
f<int>(42);
}
8

Другие решения

Вам может не понадобиться это здесь, но вот классическая техника:

struct Default
{
template <typename Argument, typename Value>
struct Get {
typedef Argument type;
};

template <typename Value>
struct Get <Default, Value> {
typedef Value type;
};
};

template <typename Out = Default, typename In>
typename Default::Get<Out, In>::type f(In x);
4

У меня есть идеальное решение здесь! f<const int&> не будет работать, потому что функция не может вернуть ссылку на временный объект, не связанный с методами, используемыми здесь.

[hidden]$ cat a.cpp
#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;

template <typename Out, typename In>
Out f_impl(In x) {
cout << "Out=" << typeid(Out).name() << " " << "In=" << typeid(In).name() << endl;
return Out();
}

template <typename T, typename... Args>
struct FirstOf {
typedef T type;
};

template <typename T, typename U>
struct SecondOf {
typedef U type;
};

template <typename... Args, typename In>
typename enable_if<sizeof...(Args) <= 1, typename FirstOf<Args..., In>::type>::type f(In x) {
typedef typename FirstOf<Args..., In>::type Out;
return f_impl<Out, In>(x);
}

template <typename... Args, typename In>
typename enable_if<sizeof...(Args) == 2, typename FirstOf<Args...>::type>::type f(In x) {
typedef typename FirstOf<Args...>::type Out;
typedef typename SecondOf<Args...>::type RealIn;
return f_impl<Out, RealIn>(x);
}

int main() {
f(1);
f(1.0);
f<double>(1);
f<int>(1.0);
f<int>(1);
f<const int>(1);
f<int, double>(1);
f<int, int>(1);
f<double, double>(1);
}
[hidden]$ g++ -std=c++11 a.cpp
[hidden]$ ./a.out
Out=i In=i
Out=d In=d
Out=d In=i
Out=i In=d
Out=i In=i
Out=i In=i
Out=i In=d
Out=i In=i
Out=d In=d
2
По вопросам рекламы [email protected]