带有更多参数的呼叫模板专业化,用于一参数模板调用的特定值

时间:2019-12-16 16:19:58

标签: c++ c++11 templates variadic-templates template-specialization

我有一个采用2个参数的模板。对于第一个参数的某个值,我知道第二个参数应该是什么。我只希望模板有一个完整的定义(一个带有2个参数的定义),并且能够实例化仅提供一个参数的模板。

在下面的示例中,我知道如果第一个模板参数为Foo1,则第二个参数应为Foo2。我希望能够通过编写Someclass<Foo1,Foo2>来创建Someclass<Foo1>

#include <iostream>
using namespace std;

struct Foo1 { Foo1() { cout << "Foo1 "; }};
struct Foo2 { Foo2() { cout << "Foo2 "; }};

template <typename ...Dummy> struct SomeClass;
template <typename T, typename U> struct SomeClass<T,U> {
  SomeClass() {
    T t;
    U u;
  }
};

/* Here, some one-argument specialization where if SomeClass<Foo1> is desired,
 * SomeClass<Foo1, Foo2> is obtained. */

int main() {
  SomeClass<Foo1, Foo2> c; //prints "Foo1 Foo2 "
  SomeClass<Foo1> c2;      //Should print the same thing, right now "incomplete type"
}

我想我将不得不进行一个专门化,它需要2个参数,第一个是Foo1,如下所示:

template <typename U> struct SomeClass<Foo1, U> {
  SomeClass() {
    Foo1 f;
    U u;
  }
};

但是我如何做一个仅接受一个参数Foo1并得到SomeClass<Foo1,Foo2>的专业化?

3 个答案:

答案 0 :(得分:5)

template <>
struct SomeClass<Foo1>:
  SomeClass<Foo1,Foo2>
{};

这将解决您描述的问题的90%。如果您需要SomeClass<Foo1>SomeClass<Foo1,Foo2>相同但又不是继承自::type,则必须编写一堆别名和template<class...Args> struct Real; template<class...Args> struct Helper { using type=Real<Args...>; }; template<class...Args> using Fake = typename Helper<Args...>::type; 杂音。

Helper

这三层是噪音。

template <typename T, typename U> struct Real<T,U> { Real() { T t; U u; } }; template<> struct Helper<Foo1>:Helper<Foo1, Foo2> {}; 使您可以重新定义参数的含义。

::type

我们在这里从Helper<Foo1, Foo2>获得了FakeHelper<Foo1>没有看到中间的Fake<Foo1>,因此我们从Real<Foo1, Foo2>获得的类型是std::is_same< Fake<Foo1>, Fake<Foo1, Foo2> >,而不是派生类。

这可确保Fake

Helper是用户使用的别名模板“ API”。 Real使您可以做一些专门化工作,以根据传入的参数选择要实例化的a = np.array(a) np.where(a[...,None]==0,[0,0,0],[255,255,255]) 模板。

答案 1 :(得分:1)

对于类模板的情况,最简单的解决方案可能是定义一个与您感兴趣的情况相匹配的特殊化,并通过继承自您想要映射到的参数将其“转发”到特殊化它:

template <typename ...Dummy>
struct SomeClass
{
    // default implementation
};

template <typename T, typename U>
struct SomeClass<T, U>
{
    // case for two parameters
};

template <> struct SomeClass<Foo1> : public SomeClass<Foo1, Foo2> {};

答案 2 :(得分:0)

如果您想避免Yakk提出的继承解决方案,则可以尝试使用第二个模板参数,其默认类型取决于第一个参数

我的意思是

template <typename T, typename U = typename DepDef<T>::type>
struct SomeClass

其中DepDef是声明的模板结构

template <typename>
struct DepDef;

Foo1的默认值是通过模板专门化定义的,如下所示

template <>
struct DepDef<Foo1>
 { using type = Foo2; };

例如,如果您希望Foo3的默认类型为Foo4,则可以添加以下专业化内容

template <>
struct DepDef<Foo3>
 { using type = Foo4; };

以下是完整的编译示例

#include <iostream>
#include <functional>

struct Foo1 { Foo1() { std::cout << "Foo1 "; } };
struct Foo2 { Foo2() { std::cout << "Foo2 "; } };
struct Foo3 { Foo3() { std::cout << "Foo3 "; } };
struct Foo4 { Foo4() { std::cout << "Foo4 "; } };

template <typename> struct DepDef;

template <> struct DepDef<Foo1> { using type = Foo2; };
template <> struct DepDef<Foo3> { using type = Foo4; };

template <typename T, typename U = typename DepDef<T>::type>
struct SomeClass
 { T t; U u; };

int main ()
 {
   SomeClass<Foo1, Foo2>  f0;
   SomeClass<Foo1, Foo3>  f1;
   SomeClass<Foo1>        f2; // default Foo2
   SomeClass<Foo3, Foo4>  f3;
   SomeClass<Foo3, Foo1>  f4;
   SomeClass<Foo3>        f5; // default Foo4
   SomeClass<Foo2, Foo1>  f6;  
   //SomeClass<Foo2>        f7; // compilation error: no default defined for Foo2
 }

观察到f7定义(最后一个)失败,因为没有为DepDef定义Foo2专门化。

如果您希望有一个通用默认值(未定义DefDep专业化时的默认值),则可以在声明内进行定义

template <typename>
struct DepDef
 { type = void; }; // generic default