[英]partial class template argument deduction in C++
I have a templated class but only part of the template arguments can be deduced from the constructor.我有一个模板 class 但只能从构造函数中推断出模板 arguments 的一部分。
Is there a way to provide the rest of the template arguments inside angle brackets when calling the constructor?有没有办法在调用构造函数时在尖括号内提供模板 arguments 的 rest ?
Assume we're using C++17.假设我们使用的是 C++17。
template<typename T1, typename T2>
struct S
{
T2 t2;
S(const T2& _t2) : t2{_t2} {}
void operator()(const T1& t1)
{
std::cout << t1 << ", " << t2 << '\n';
}
};
int main()
{
S<int, double> s {3.14};
std::function<void(int)> func = s;
func(42);
// What I want:
//S<int> s2 {3.14}; <- T1 is provided in the angle brackets, T2 is deduced
//std::function<void(int)> func2 = s;
//func2(42);
}
As far as I know we need to either provide all the template arguments in angle brackets or none of them and use CTAD.据我所知,我们需要在尖括号中提供所有模板 arguments,或者不提供任何模板并使用 CTAD。 The problem is that I don't want to write all the template arguments (in my actual use case there's like 5-6 of them and they are quite verbose) but I also don't want to pass all the arguments in the constructor because some of them are not used to construct the object.问题是我不想编写所有模板 arguments (在我的实际用例中,它们中有 5-6 个,它们非常冗长)但我也不想在构造函数中传递所有 arguments 因为其中一些不用于构建 object。 I just need their types for the operator() method.对于 operator() 方法,我只需要它们的类型。
I cannot make the operator() method templated because I want to bind it to a std::function object and I cannot deduce the template parameter types during the bind.我无法将 operator() 方法模板化,因为我想将它绑定到 std::function object 并且我无法在绑定期间推断模板参数类型。 So that's why I need all the types in the wrapping class.所以这就是为什么我需要包装 class 中的所有类型。
This partial template deduction exists for functions.这种部分模板推导存在于函数中。
For example:例如:
template<typename T1, typename T2>
void foo(const T2& t2)
{
T1 t1{};
std::cout << t1 << ", " << t2 << '\n';
}
int main()
{
foo<int>(3.4); //T1 is explicitly int, T2 is deduced to be double
}
My current solution is to exploit this feature and construct the object through a function:我目前的解决方案是利用此功能并通过 function 构建 object:
template<typename U1, typename U2>
S<U1, U2> construct_S(const U2& t2)
{
return S<U1, U2>{t2};
}
int main()
{
auto s2 = construct_S<int>(1.5);
std::function<void(int)> func2 = s2;
func2(23);
}
I find this solution clumsy because we're using an external function to construct the object.我发现这个解决方案很笨拙,因为我们使用外部 function 来构建 object。
I was wondering if there's a cleaner solution for doing this.我想知道是否有更清洁的解决方案可以做到这一点。
Maybe something with deduction guides?也许有扣除指南的东西? I'm not sure.我不确定。
As mentioned in a comment, you can use a nested class such that the two parameters can be provided seperately (one explicitly the other deduced):如评论中所述,您可以使用嵌套的 class 以便可以单独提供两个参数(一个显式推导出另一个):
template<typename T1>
struct S {
template <typename T2>
struct impl {
T2 t2;
impl(const T2& _t2) : t2{_t2} {}
};
template <typename T2>
impl(const T2&) -> impl<T2>;
};
int main() {
S<int>::impl<double> s {3.14};
S<int>::impl s2 {3.14}; // <- T1 is provided in the angle brackets, T2 is deduced
}
I found this How to provide deduction guide for nested template class?我发现这个如何为嵌套模板 class 提供推演指南? . . Though, the above code compiles without issues with both gcc and clang: https://godbolt.org/z/MMaPYGbe1 .尽管如此,上面的代码在 gcc 和 clang 编译时都没有问题: https://godbolt.org/z/MMaPYGbe1 。
If refactoring the class template is not an option, the helper function is a common and clean solution.如果重构 class 模板不是一个选项,帮助程序 function 是一个常见且干净的解决方案。 The standard library has many make_xxx
functions, some of them were only needed before CTAD was a thing.标准库有许多make_xxx
函数,其中一些仅在 CTAD 出现之前才需要。
The simplest way is to provide factory function which will take over deduction of types:最简单的方法是提供工厂function,它将接管类型的扣除:
template<typename T1, typename T2>
auto makeS(T2 x) -> S<T1, T2>
{
return S<T1, T2>{x};
}
https://godbolt.org/z/4cPTdv7e3 https://godbolt.org/z/4cPTdv7e3
template<typename T2>
struct S
{
T2 t2;
S(const T2& _t2) : t2{_t2} {}
template<typename T1>
void operator()(const T1& t1)
{
std::cout << t1 << ", " << t2 << '\n';
}
};
int main()
{
S s {3.14}; // T1 not provided
std::function<void(int)> func2 = s; // T1 deduced by std function
func2(42); // works
}
I just removed T1
and made it a template argument of operator()
and everything works.我刚刚删除了T1
并将其作为operator()
的模板参数,一切正常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.