如何仅通过其中一种类型来引用具有多个模板类型的 class?
How do I refer to a class with multiple template types by only one of the types?
假设我有一个 class Shape
声明:
template <typename T, typename U, typename V>
class Shape {
T value;
U input;
V input2;
...
}
实际上,如果我创建一个 Shape
对象,它的类型将类似于 Shape<int, float, double>
- 例如。
但是,如果我希望能够创建一个 Shape
对象并仍然为其提供不同类型的输入(例如 float
和 double
),但我想要它的类型怎么办?成为 Shape<int>
.
也就是说,在创建一个 Shape
对象之后,我希望调用者只关心它的值的类型,而不关心它的输入的类型。你建议我怎么做?
我了解到,如果不在顶部声明模板类型,我就无法存储模板成员变量。我也尝试过使用像这样的别名:
template <typename T, typename U, typename V>
using ShapeAlias<T> = Shape<T, U, V>
但这也不管用。你对我如何处理这件事有什么建议吗?
我正在考虑某种形式的继承,其中有一个基 class 只有一种类型,派生的 class 包含所有三种类型,但我想我应该在这里检查。
编辑:我需要第二种和第三种类型,因为用户可以将函数传递给 Shape
构造函数来计算 T 的值,它看起来像:
auto creator = [](U a, V b){
return (something of type T)
}
我想将输入类型的值保留在 Shape
class 中。
所以从客户的角度来看,他们的代码应该是这样的:
Shape<T> shapeA(Shape<T>(uValue, vValue, creator)
像现在这样,他们将不得不做:
Shape<T, U, V> shapeA(Shape<T, U, V>(uValue, vValue, creator))
您似乎在寻找 CTAD(class 模板参数推导)。它仅在调用者未指定任何模板参数时有效,因此必须添加一个间接层:
template <typename T>
struct ShapeWrap {
template <typename U,typename V>
struct Shape {
T value;
U input;
V input2;
Shape(const U& u,const V& v) : input(u),input2(v) {}
};
};
来电者现在可以拨打:
auto s = ShapeWrap<int>::Shape(1.0,0.1f);
实例化ShapeWrap<int>::Shape<double,float>
.
或者通过函数模板的模板参数推导:
template <typename T, typename U,typename V>
struct Shape {
T value;
U input;
V input2;
Shape(const U& u,const V& v) : input(u),input2(v) {}
};
template <typename T,typename U,typename V>
Shape<T,U,V> make_shape(const U& u, const V& v) {
return {u,v};
}
int main() {
auto s = make_shape<int>(1.0,0.1f);
}
如果创建者对象仅在构造函数本身中使用,但您不需要存储值供以后使用,则可以求助于模板化构造函数。如果您确实需要存储值,则需要指定包括所有类型参数在内的完整类型,如果用户必须自己命名类型。您可以以 auto
可用的方式设计 class。
备选方案 1:创建用于创建对象的函数。
这允许用户从左侧开始指定一些模板参数,但其余部分由编译器推导。
template<class Product, class CreatorType, class ...Args>
class Factory
{
public:
Factory(CreatorType const& creator, Args...args)
: m_creator(creator), m_arguments(args...)
{
}
Product Create()
{
return std::apply(m_creator, m_arguments);
}
private:
CreatorType m_creator;
std::tuple<Args...> m_arguments;
};
template<class Product, class CreatorType, class ...Args>
auto CreateFactory(CreatorType const& creator, Args ... args)
{
return Factory<Product, CreatorType, Args...>(creator, args...);
}
int main() {
auto creator = [](int value) -> int { return value + 1; };
auto factory = CreateFactory<long>(creator, 41); // we're able do add a type conversion int -> long here
std::cout << "The answer is " << factory.Create() << '\n';
}
备选方案 2:添加 class 模板参数推导 (CTAD) 指南
如果您同意根据调用创建者的结果自动推导 return 类型,您可以创建一个自动推导类型参数的 CTAD 指南,如果用户未指定任何模板参数。
template<class Product, class CreatorType, class ...Args>
class Factory
{
public:
Factory(CreatorType const& creator, Args const&...args)
: m_creator(creator), m_arguments(args...)
{
}
Product Create()
{
return std::apply(m_creator, m_arguments);
}
private:
CreatorType m_creator;
std::tuple<Args...> m_arguments;
};
// deduction guideline: the result of calling creator with the arguments is used as the first template parameter
template<class CreatorType, class ... Args>
Factory(CreatorType const&, Args const&...) -> Factory<decltype(std::apply(std::declval<CreatorType>(), std::declval<std::tuple<Args...>>())), CreatorType, Args...>;
int main() {
auto creator = [](int value) -> int { return value + 1; };
Factory factory(creator, 41); // type of factory automatically chosen to be Factory<int, ..., int>
std::cout << "The answer is " << factory.Create() << '\n';
}
假设我有一个 class Shape
声明:
template <typename T, typename U, typename V>
class Shape {
T value;
U input;
V input2;
...
}
实际上,如果我创建一个 Shape
对象,它的类型将类似于 Shape<int, float, double>
- 例如。
但是,如果我希望能够创建一个 Shape
对象并仍然为其提供不同类型的输入(例如 float
和 double
),但我想要它的类型怎么办?成为 Shape<int>
.
也就是说,在创建一个 Shape
对象之后,我希望调用者只关心它的值的类型,而不关心它的输入的类型。你建议我怎么做?
我了解到,如果不在顶部声明模板类型,我就无法存储模板成员变量。我也尝试过使用像这样的别名:
template <typename T, typename U, typename V>
using ShapeAlias<T> = Shape<T, U, V>
但这也不管用。你对我如何处理这件事有什么建议吗?
我正在考虑某种形式的继承,其中有一个基 class 只有一种类型,派生的 class 包含所有三种类型,但我想我应该在这里检查。
编辑:我需要第二种和第三种类型,因为用户可以将函数传递给 Shape
构造函数来计算 T 的值,它看起来像:
auto creator = [](U a, V b){
return (something of type T)
}
我想将输入类型的值保留在 Shape
class 中。
所以从客户的角度来看,他们的代码应该是这样的:
Shape<T> shapeA(Shape<T>(uValue, vValue, creator)
像现在这样,他们将不得不做:
Shape<T, U, V> shapeA(Shape<T, U, V>(uValue, vValue, creator))
您似乎在寻找 CTAD(class 模板参数推导)。它仅在调用者未指定任何模板参数时有效,因此必须添加一个间接层:
template <typename T>
struct ShapeWrap {
template <typename U,typename V>
struct Shape {
T value;
U input;
V input2;
Shape(const U& u,const V& v) : input(u),input2(v) {}
};
};
来电者现在可以拨打:
auto s = ShapeWrap<int>::Shape(1.0,0.1f);
实例化ShapeWrap<int>::Shape<double,float>
.
或者通过函数模板的模板参数推导:
template <typename T, typename U,typename V>
struct Shape {
T value;
U input;
V input2;
Shape(const U& u,const V& v) : input(u),input2(v) {}
};
template <typename T,typename U,typename V>
Shape<T,U,V> make_shape(const U& u, const V& v) {
return {u,v};
}
int main() {
auto s = make_shape<int>(1.0,0.1f);
}
如果创建者对象仅在构造函数本身中使用,但您不需要存储值供以后使用,则可以求助于模板化构造函数。如果您确实需要存储值,则需要指定包括所有类型参数在内的完整类型,如果用户必须自己命名类型。您可以以 auto
可用的方式设计 class。
备选方案 1:创建用于创建对象的函数。
这允许用户从左侧开始指定一些模板参数,但其余部分由编译器推导。
template<class Product, class CreatorType, class ...Args>
class Factory
{
public:
Factory(CreatorType const& creator, Args...args)
: m_creator(creator), m_arguments(args...)
{
}
Product Create()
{
return std::apply(m_creator, m_arguments);
}
private:
CreatorType m_creator;
std::tuple<Args...> m_arguments;
};
template<class Product, class CreatorType, class ...Args>
auto CreateFactory(CreatorType const& creator, Args ... args)
{
return Factory<Product, CreatorType, Args...>(creator, args...);
}
int main() {
auto creator = [](int value) -> int { return value + 1; };
auto factory = CreateFactory<long>(creator, 41); // we're able do add a type conversion int -> long here
std::cout << "The answer is " << factory.Create() << '\n';
}
备选方案 2:添加 class 模板参数推导 (CTAD) 指南
如果您同意根据调用创建者的结果自动推导 return 类型,您可以创建一个自动推导类型参数的 CTAD 指南,如果用户未指定任何模板参数。
template<class Product, class CreatorType, class ...Args>
class Factory
{
public:
Factory(CreatorType const& creator, Args const&...args)
: m_creator(creator), m_arguments(args...)
{
}
Product Create()
{
return std::apply(m_creator, m_arguments);
}
private:
CreatorType m_creator;
std::tuple<Args...> m_arguments;
};
// deduction guideline: the result of calling creator with the arguments is used as the first template parameter
template<class CreatorType, class ... Args>
Factory(CreatorType const&, Args const&...) -> Factory<decltype(std::apply(std::declval<CreatorType>(), std::declval<std::tuple<Args...>>())), CreatorType, Args...>;
int main() {
auto creator = [](int value) -> int { return value + 1; };
Factory factory(creator, 41); // type of factory automatically chosen to be Factory<int, ..., int>
std::cout << "The answer is " << factory.Create() << '\n';
}