在两个本身就是模板的模板类型参数之间强制使用通用模板类型参数

问题描述 投票:0回答:2

在C++中,有什么方法可以确保两个或多个模板类型参数本身就是具有公共模板类型参数的模板类型?

假设我有这个:

struct ArbitraryType {};

template <typename T>
class ArbitraryTemplateClass1 {
  /* ... */
};

template <typename T>
class ArbitraryTemplateClass2 {
  /* ... */
};

我想要一个可以将

ArbitraryTemplateClass1
ArbitraryTemplateClass2
作为模板类型参数的模板,但确保它们都有一个通用的模板类型参数
T
(然后使用类型
T
执行某些操作)。例如,我希望能够做类似的事情:

template <typename U <typename T>, typename V<T>> // desired (but incorrect) syntax
struct CommonTemplateTypeParameterProducer {
  T Produce() { return T(); }
};

// Which would allow this:
int main() {
  CommonTemplateTypeParameterProducer<ArbitraryTemplateClass1<ArbitraryType>, 
                                      ArbitraryTemplateClass2<ArbitraryType>> producer;

  // Type of t should be ArbitraryType
  auto t = producer.Produce();

  // This should fail to instantiate CommonTemplateTypeParameterProducer because U and V don't share a common T
  //CommonTemplateTypeParameterProducer<ArbitraryTemplateClass1<ArbitraryType>, 
  //                                    ArbitraryTemplateClass2<int>>         producer2; 

}

是否有任何机制允许这种行为,而无需直接了解任意模板类和任意类型? (像向

ArbitraryTemplateClass1
添加 typedef 来指定
T
的类型之类的做法是不可行的)。如果可能的话,我还想避免向
CommonTemplateTypeParameterProducer;
添加第三个模板类型参数,理想情况下我希望模板能够推断出它正在执行的常见类型。

注意:这样的东西也有助于确保两个同样是可变参数模板的模板类型参数都具有相同的模板参数。

我研究了 C++ 概念/约束/要求和模板模板参数,但到目前为止似乎没有一个为这个特定问题提供解决方案。

c++ templates type-parameter template-templates
2个回答
0
投票

这是可能的,但可能不是最好的设计,因为如果有人需要向 ArbitraryTemplateClass1 添加

another
模板参数,一切都会崩溃。或者,如果您决定制作一个未模板化的版本,并且仅适用于一种特定类型。

最好将

using type = T;
之类的内容添加到
ArbitraryTemplateClass1
/
2
中,并在模板中检查它而不是实际的模板参数。
CommonTemplateTypeParameterProducer
不应该监管其模板参数的模板参数。

#include <concepts>

template <typename T>
struct A
{
    using type = T;
};

template <typename T>
struct B
{
    using type = T;
};

template <typename X, typename Y>
requires std::same_as<typename X::type, typename Y::type>
struct Foo
{
    X x;
    Y y;
};

int main()
{
    Foo<A<int>, B<int>> foo;
}

这是另一种选择。它与您提出的设计有相同的问题,但至少您不需要将模板参数拼写两次:

template <typename T>
struct A {};

template <typename T>
struct B {};

template <
    template <typename> typename X,
    template <typename> typename Y,
    typename T
>
struct Foo
{
    X<T> x;
    Y<T> y;
};

int main()
{
    Foo<A, B, int> foo;
}

最后,这正是您所要求的。我添加了一个辅助模板来从任意模板中提取模板参数。这又存在我上面描述的问题,并且还需要将模板参数拼写两次。

#include <concepts>

template <typename T>
struct GetTemplateArgument {};
template <template <typename> typename T, typename U>
struct GetTemplateArgument<T<U>> {using type = U;};

template <typename T>
struct A {};

template <typename T>
struct B {};

template <typename X, typename Y>
requires std::same_as<typename GetTemplateArgument<X>::type, typename GetTemplateArgument<Y>::type>
struct Foo
{
    X x;
    Y y;
};

int main()
{
    Foo<A<int>, B<int>> foo;
}

0
投票

您可以通过符合要求的部分专业化来做到这一点。

使用带有 2 个类型参数的主类。不要定义它,所以如果你尝试使用它,你会得到一个错误:

template <typename, typename>
struct CommonTemplateTypeParameterProducer;

然后编写一个部分特化,它采用 2 个模板参数

A
B
,以及 1 个类型参数
T
。如果变量声明中使用的类型与模式
A<T>
B<T>
匹配,则将选择此专业化:

template <template <typename> typename A,
          template <typename> typename B,
          typename T>
struct CommonTemplateTypeParameterProducer<A<T>, B<T>> 
{
  T Produce() { return T(); }
};

这是一个演示

© www.soinside.com 2019 - 2024. All rights reserved.