我的实际用例需要更多参数,但它简化为:
template< typename Arg1 >
bool algorithm( Arg1&& p1, **p2 here** );
很明显,Arg1会以某种方式崩溃,并可能成为某种参考。 p1也是算法的输出,因此如果调用者选择传入左值,函数将返回并修改原始参数以反映它停止的位置。
然而,p2属于同一类型,但永远不会被修改。所以实际上我想在那里放一个'const'的承诺来保证正确性。显然,如果Arg1推断为参考,我不能添加const。
所以我的解决方案是:
template< class T >
struct make_const_ref
{
typedef typename std::add_reference< typename std::add_const< typename std::remove_reference< T >::type >::type >::type type;
};
template< typename Arg1 >
bool algorithm( Arg1&& p1, typename make_const_ref<Arg1>::type p2 );
通过一系列愚蠢的阴谋去除一些限定符,然后坚持const&amp;回来。
所以我的问题是:
1)这是最好的方式吗?
2)是否存在失败的背景?现在对我来说似乎很不错。
答案 0 :(得分:0)
我可以想到一个令人惊讶的变化,但不会导致彻底的失败。从参数推导中禁用第二个参数,因此类型不再必须与第一个参数类型完全匹配。这允许接受隐式转换,如果为函数指定了模板参数。一个例子:
struct Foo
{
int value;
operator int() const
{
return value;
}
};
int main()
{
algorithm(0, Foo{0});
}
而表达式:
template<typename Arg>
bool algorithm(const Arg& p1, const Arg2& p2)
除非明确algorithm(0, Foo{0})
,否则将无法使用algorithm<int>(0, Foo{0})
进行编译。如果你只希望完全匹配,那么这可能会有问题。在某些情况下这是可取的; boost::clamp是我所知道的一个有意识的例子。
这与您的问题的一些评论类似,但可以简化特征:
template<typename Type>
using const_ref_t =
typename std::add_const<
typename std::add_lvalue_reference<Type>::type>::type;
std::add_lvalue_reference会在所有情况下做你想做的事。
我把它作为评论,但它可能应该放在这里。这可能更容易:
template<typename Arg1>
bool algorithm(Arg1&& p1, const typename std::remove_reference<Arg1>::type& p2)
您要做的就是禁用第二个参数的参数推导,并通过const-reference获取它。这就是这样做的。