如果不实际使用通用引用,您将无法获得“通用引用”的优势,因此只需将Container
其设为“通用引用”参数。如果您这样做,您需要做的就是使用另一种技术来查找N
.
一种选择是简单地Container
存储N
在static
变量中(或在typedef
'dstd::integral_constant
或constexpr
函数中)。另一种选择是编写一个新的(元)函数,其唯一目的是查找N
. 我更喜欢第一个选项,但我会在答案中写下第二个选项,因为它的侵入性较小(它不需要对 进行任何更改Container
)。
//This can alternatively be written as a trait struct.
template
< template<class, std::size_t, class...> class Container
, class Type
, std::size_t N
, class... Args >
constexpr std::size_t get_N(Container<Type, N, Args...> const&) { return N; }
template <class Container>
auto func(std::size_t i, Container &&container) -> decltype(container[i]) {
//alternatively, use std::tuple_size or container.size() or whatever
constexpr std::size_t N = get_N(container);
static_assert(N >= 40 && N <= 42, "bla bla bla");
return container[i];
}
现在您需要能够container[i]
使用 cv-ness 和 value 类别进行转发container
。为此,请使用作为std::forward
. 这真的很难看,因为标准库中对此没有太多支持(幸运的是,您只需要编写一次,它对于很多不同的问题都很有用)。首先类型计算:
template<typename Prototype, typename T_value, typename T_decayed>
using forward_Const_t =
typename std::conditional<
std::is_const<Prototype>::value || std::is_const<T_value>::value,
T_decayed const,
T_decayed
>::type;
template<typename Prototype, typename T_value, typename T_decayed>
using forward_CV_t =
typename std::conditional<
std::is_volatile<Prototype>::value || std::is_volatile<T_value>::value,
forward_Const_t<Prototype, T_value, T_decayed> volatile,
forward_Const_t<Prototype, T_value, T_decayed>
>::type;
template<typename Prototype, typename T>
struct forward_asT {
static_assert(
std::is_reference<Prototype>::value,
"When forwarding, we only want to be casting, not creating new objects.");
static_assert(
!(std::is_lvalue_reference<Prototype>::value &&
std::is_rvalue_reference<T>::value),
"Casting an rvalue into an lvalue reference is dangerous");
typedef typename std::remove_reference<Prototype>::type Prototype_value_t;
typedef typename std::decay<T>::type T_decayed;
typedef typename std::remove_reference<T>::type T_value;
typedef typename std::conditional<
std::is_lvalue_reference<Prototype>::value,
forward_CV_t<Prototype_value_t, T_value, T_decayed> &,
forward_CV_t<Prototype_value_t, T_value, T_decayed> &&>::type type;
};
template<typename Prototype, typename T>
using forward_asT_t = typename forward_asT<Prototype,T>::type;
现在的功能:
//Forwards `val` with the cv qualification and value category of `Prototype`
template<typename Prototype, typename T>
constexpr auto forward_as(T &&val) -> forward_asT_t<Prototype, T &&> {
return static_cast<forward_asT_t<Prototype, T &&>>(val);
}
现在已经定义了辅助函数,我们可以简单地写成func
:
template <typename Container>
auto func(std::size_t i, Container &&container) ->
decltype(forward_as<Container &&>(container[i]))
{
constexpr std::size_t N = get_N(container);
static_assert(N >= 40 && N <= 42, "bla bla bla");
return forward_as<Container &&>(container[i]);
}