Geo*_*rge 15 c++ templates metaprogramming template-meta-programming c++17
假设以下情况:
类型A和类型B,B可以隐式转换为A但反之则是不真实的.
我有一个功能
template<class T>
void do_stuff(T a, T b);
Run Code Online (Sandbox Code Playgroud)
我想这样调用所述函数:
do_stuff(A{}, B{});
Run Code Online (Sandbox Code Playgroud)
这里的问题是编译器无法推断出类型,而是说:
template argument deduction/substitution failed
Run Code Online (Sandbox Code Playgroud)
我可以这样调用我的函数:
do_stuff<A>(A{}, B{});
Run Code Online (Sandbox Code Playgroud)
但这对用户来说更烦人.
或者我可以做这样的事情:
template<class T, class M>
void do_stuff(T a, M b);
Run Code Online (Sandbox Code Playgroud)
但是b继续以它的快乐方式成为B类(具有先前的调用).
理想情况下,我想要像:
template<class T, class M = T>
void do_stuff(T a, M b);
Run Code Online (Sandbox Code Playgroud)
要么:
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);
Run Code Online (Sandbox Code Playgroud)
这样的事情可能吗?
Bar*_*rry 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);
Run Code Online (Sandbox Code Playgroud)
C++ 11中有答案:http:std::common_type
//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
}
Run Code Online (Sandbox Code Playgroud)
只需要一个小团队,这当然是可能的.通过指定您总是希望推断类型是第一个参数的类型,您已经非常容易地解决了问题,因此我们需要做的就是向编译器稍微提示一下.
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);
}
Run Code Online (Sandbox Code Playgroud)
现在用户可以调用do_stuff任何两个参数,C++将尝试隐式转换第二个参数以匹配第一个参数的类型.如果强制转换无效,您将收到模板实例化错误.它说cannot convert ‘b’ (type ‘A’) to type ‘B’,在海湾合作委员会,这是非常准确和重点.任何有价值的编译器都能够内联该委托调用,因此应该有可忽略不计的开销.