vector<int> g(int float); char g(string&, int); template <typename ... T> T* g(T, T*);
template <typename ... T> ??? f(T&& ... args) { return g(std::forward<T>(args) ...) }
Что ставить на место ???
С простыми типами можно:
typename std::common_type<U, V>::type max(U const& u, V const& v) {
return u < v ? v : u;
}
Есть встроенная возможность:
template <typename ... T>
decltype(g(std::forward<T>(args) ...)) f(T&& ... args) {
return g(std::forward<T>(args) ...);
}
Но вот проблема, args
используется до объявления
В c++11
появилась возможность указать тип возвращаемого значения после объявления функции (trailing return type)
template <typename ... T>
auto f(T&& ... args) -> decltype(g(std::forward<T>(args) ...)) {
return g(std::forward<T>(args) ...);
}
А что если мы не хотим использовать args
?
template <typename ... T>
auto f(T&& ... args) -> decltype(g(std::forward<T>(T()) ...)) {
return g(std::forward<T>(args) ...);
}
Не работает из-за: 1) может отсутствовать конструктор по умолчанию, 2) args - lvalue
, T() - rvalue
Выход?
tepmlate<typename T> T& declval();
template <typename ... T> auto f(T&& ... args) -> decltype(g(std::forward<T>(declval(T)) ...)) { return g(std::forward<T>(args) ...); }
Такая штука может использоваться только в non-evaluating context
В c++14
появилась возможность делать просто
template <typename ... T>
auto f(T&& ... args) {
return g(std::forward<T>(args) ...);
}
Хоть и компактно, но перестает работать для SFINAE
Существует 2 формы decltype
- decltype(var) - возвращает просто тип переменной
- decltype(expr)
НЕОЖИДАННО НАМ ВРАЛИ
Что возвращает этот decltype?
prvalue - T, decltype(a) = int
lvalue - T&, decltype((a)) = int&
xvalue - T&&
(rvalue находящийся на грани уничтожения)
T f() T a = f(); //f() - prvalue, можем не вызывать конструктор
T<span class="token operator">&&</span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> T a <span class="token operator">=</span> <span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// f() - xvalue, не можем не вызывать конструктор</span>
Можно инициализировать нулевой указатель нулем
Но тут возникают проблемы с перегрузками по int
и void*
, а также с perfect forwarding
по тем же параметрам
Появился nullptr, который имеет свой собственный тип nullptr_t, который может приводиться к указателю на любой тип
struct foo { int bar(int a) { return a; } };
int (foo:: p)(int) = (&foo::bar);
foo v;
(v.p)(5);
foo p (v->p)(10);