简体   繁体   English

如何仅通过其中一种类型引用具有多种模板类型的 class?

[英]How do I refer to a class with multiple template types by only one of the types?

Let's say I have a class Shape with the declaration:假设我有一个带有声明的 class Shape

template <typename T, typename U, typename V>
class Shape {
   T value;
   U input;
   V input2;

   ...
}

As it is, if I create a Shape object, its type will be something like Shape<int, float, double> - for example.事实上,如果我创建一个Shape object,它的类型将类似于Shape<int, float, double> - 例如。

But what if I want to be able to create a Shape object and still give it inputs of different types (like float and double ), but I want its type to be Shape<int> .但是,如果我希望能够创建一个Shape object 并仍然为其提供不同类型的输入(如floatdouble ),但我希望其类型为Shape<int>怎么办?

That is, after creating a Shape object, I want callers to only care about the type of its value, not the type of its inputs.也就是说,在创建Shape object 之后,我希望调用者只关心其值的类型,而不关心其输入的类型。 How do you suggest I go about it?你怎么建议我go一下呢?

I've learned that I cannot store templates member variables without having declared the template types at the top.我了解到,如果不在顶部声明模板类型,我就无法存储模板成员变量。 I've also attempted using an alias like:我也尝试过使用别名,例如:

template <typename T, typename U, typename V>
using ShapeAlias<T> = Shape<T, U, V>

But that doesn't work either.但这也不管用。 Do you have any suggestions on how I can go about this?你对我如何能 go 有什么建议吗?

I'm considering some form of inheritance where there's a base class with only one of the types, and the derived class contains all three types, but I thought I should check here.我正在考虑某种形式的 inheritance,其中有一个只有一种类型的基 class,而派生的 class 包含所有三种类型,但我想我应该在这里检查。

Edit: I need the second and third types because the idea is that a user will be able to pass a function to a Shape constructor to calculate the value of T, which could look like:编辑:我需要第二种和第三种类型,因为用户可以将 function 传递给Shape构造函数来计算 T 的值,它可能如下所示:

auto creator = [](U a, V b){
   return (something of type T)
}

And I want to keep the values of the input types in the Shape class.我想将输入类型的值保留在Shape class 中。

So from a client's perspective, their code should look like this:所以从客户的角度来看,他们的代码应该是这样的:

Shape<T> shapeA(Shape<T>(uValue, vValue, creator)

As it is now, they would have to do:就像现在一样,他们必须这样做:

Shape<T, U, V> shapeA(Shape<T, U, V>(uValue, vValue, creator))

It seems like you are looking for CTAD (class template argument deduction).看起来您正在寻找 CTAD(类模板参数推导)。 It only works when the caller does not specify any template argument, hence a layer of indirection has to be added:它仅在调用者未指定任何模板参数时有效,因此必须添加一个间接层:

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) {}
    };
};

Caller can now call:调用者现在可以调用:

auto s = ShapeWrap<int>::Shape(1.0,0.1f);

To instantiate ShapeWrap<int>::Shape<double,float> .实例化ShapeWrap<int>::Shape<double,float>


Alternatively via template argument deduction of a function template:或者通过 function 模板的模板参数推导:

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);
}

If the creator object is only used in the constructor itself, but you don't need to store the values for later use, you could just resort to a templated constructor.如果创建者 object 仅在构造函数本身中使用,但您不需要存储值供以后使用,则可以求助于模板化构造函数。 If you do need to store the value the full type including all type parameters need to be specified, if the user has to name the type themselves.如果您确实需要存储值,则需要指定包括所有类型参数在内的完整类型,如果用户必须自己命名类型。 You could design the class in a way for auto to be useable.您可以设计 class 使auto可用。

Alternative 1: Create a function for creating the object.备选方案 1:创建 function 以创建 object。

This allows the user to specify some of the template parameters starting from the left, but having the rest deduced by the compiler.这允许用户从左侧开始指定一些模板参数,但编译器会推导出 rest。

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';
}

Alternative 2: Add a class template argument deduction (CTAD) guideline备选方案 2:添加 class 模板参数推导 (CTAD) 指南

If you're ok with having the return type automatically be deduced based on the result of invoking the creator, you could create a CTAD guideline automatically deducing the type parameters, if the user does not specify any of the template parameters.如果您同意根据调用创建者的结果自动推导返回类型,则可以创建一个自动推导类型参数的 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';
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM