3

考虑这两个模板函数:

template<typename T>
void foo(T&& bar) {
    // do stuff with bar, which may or may not be an instance of a templated class
}

template<typename U, template<typename> class T>
void foo(T<U>&& bar) {
    // do stuff with bar, which must be an instance of a templated class
}

为什么前者接受左值(通过使用转发引用)而后者不接受?


看起来身份别名模板可以作为转发参考吗?也可能与此有关,但它似乎涵盖了转发引用限制的不同方面。

4

2 回答 2

3

如果你想保留一个转发引用参数,同时推导出一个参数的类型,你可以使用下面的解决方案:

#include <type_traits>
#include <utility>

template <typename T>
struct tag {};

template <typename T, typename U, template <typename> class C>
void foo(T&& t, tag<C<U>>)
{

}

template <typename T>
auto foo(T&& t)
    -> decltype(foo(std::forward<T>(t), tag<typename std::decay<T>::type>{}))
{
    return foo(std::forward<T>(t), tag<typename std::decay<T>::type>{});
}

演示

于 2016-02-27T16:16:29.963 回答
2

因为这就是标准所说的语言应该如何工作的方式。

[14.8.2.1][temp.deduct.call]
3.如果 P 是 cv 限定类型,则忽略 P 类型的顶级 cv 限定符进行类型推导。如果 P 是引用类型,则使用 P 所引用的类型进行类型推导。转发引用是对 cv 非限定模板参数的右值引用。如果 P 是转发引用并且参数是左值,则使用类型“对 A 的左值引用”代替 A 进行类型推导。

以这种方式,只有对 CV 非限定模板参数的右值引用可以推断为左值引用。

为了实现您想要做的事情,您可以使用特征来提取模板模板参数。

#include <type_traits>

/***
 * Extract template from template type.
 */
template <typename I> struct get_template;

template <template<class> typename T, typename C>
struct get_template<T<C>> {
  template <typename U>
  using temp = T<U>;
};





template <typename T> struct A{};

struct B;

template<typename W>
void foo(W && bar) {
  typedef typename get_template<typename std::remove_reference<W>::type>::template temp<int> new_type;
  new_type my_variable;
}

int main() {
  A<B> temp;
  foo(temp);
}

或者,像往常一样重载 const & 和 && 的函数。

于 2016-02-27T06:37:47.540 回答