假设以下情况:
键入A
并输入B
,B
可以隐式转换为A
,但反之则不真实。
我有一个功能
template<class T>
void do_stuff(T a, T b);
我想这样称呼这个函数:
do_stuff(A{}, B{});
这里的问题是编译器无法推断出类型,而是说:
template argument deduction/substitution failed
我可以这样调用我的函数:
do_stuff<A>(A{}, B{});
但这对用户来说更烦人。
或者我可以这样做:
template<class T, class M>
void do_stuff(T a, M b);
然后b继续以快乐的方式成为B类(使用先前的调用)。
理想情况下,我想要像:
template<class T, class M = T>
void do_stuff(T a, M b);
或者:
template<class T@INSERT MAGIC SO THAT T IS DEDUCED AS BEING THE TYPE OF ARGUMENT NR 1@>
void do_stuff(T a, T b);
这样的事情可能吗?
答案 0 :(得分:21)
在未推断的上下文中包装b
。这样,只会推断出a
,并且b
必须转换为该类型。
template <class T> struct dont_deduce { using type = T; };
template <class T> using dont_deduce_t = typename dont_deduce<T>::type;
template<class T>
void do_stuff(T a, dont_deduce_t<T> b);
答案 1 :(得分:8)
C ++ 11中有答案:std::common_type
http://en.cppreference.com/w/cpp/types/common_type
template<typename A>
void f_impl(A a, A b)
{
}
template<typename A, typename B>
void f(A a, B b)
{
f_impl<typename std::common_type<A, B>::type>(a, b);
}
struct Z
{
};
struct W
{
operator Z();
};
int main()
{
f(1u, 1l); //work
f(W{}, Z{});
f(Z{}, W{}); //and this work too
}
答案 2 :(得分:7)
当然只有一个小团队,这当然是可能的。通过指定您总是希望推断类型是第一个参数的类型,您已经很容易地解决了这个问题,所以我们需要做的就是给编译器稍微提示一下。
let newObject = {
configuration: {
'11111-2222-3333-444--5555': o.configuration['11111-2222-3333-444--5555']
}
}
现在用户可以使用任意两个参数调用template <class T>
void do_stuff_impl(T a, T b) {
cout << "Doing some work..." << endl;
}
template <class T, class S>
void do_stuff(T a, S b) {
do_stuff_impl<T>(a, b);
}
,C ++将尝试隐式转换第二个参数以匹配第一个参数的类型。如果演员表无效,您将获得模板实例化错误。在海湾合作委员会,它说do_stuff
,这是非常准确和重点。任何有价值的编译器都能够内联委托调用,因此开销应该可以忽略不计。
答案 3 :(得分:1)
另一种方式,寻求以声明方式表达意图:
#include <type_traits>
// a B
struct B{};
// an A can be constructed from a B
struct A{
A() {};
A(B) {};
};
// prove that A is constructible from B
static_assert(std::is_convertible<B, A>::value, "");
// enable this function only if a U is convertible to a T
template<
// introduce the actors
class T, class U,
// declare intent
std::enable_if_t<std::is_convertible<U, T>::value>* = nullptr
>
void do_stuff(T, U)
{
}
int main()
{
// legal
do_stuff(A{}, B{});
// does not compile
// do_stuff(B{}, A{});
}
更新
要强制转换,可以使用lambda:
// enable this function only if a U is convertible to a T
template<class T, class U,
std::enable_if_t<std::is_convertible<U, T>::value>* = nullptr
>
void do_stuff(T a, U b)
{
return[](T& a, T b) -> decltype(auto)
{
}(a, b);
}