Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板类型定义?_C++_Templates_Specialization - Fatal编程技术网

C++ 模板类型定义?

C++ 模板类型定义?,c++,templates,specialization,C++,Templates,Specialization,在外部API中,我定义了结构: Foo1,Foo4,Foo8,Foo16 现在我需要定义四个函数: void bar(Foo1*); void bar(Foo4*); void bar(Foo8*); void bar(Foo16*); 这些函数在循环中重复1、4、8和16次执行相同的操作 为了避免编写这些函数4次,我很乐意使用一个模板来定义它们: template<unsigned int N> void bar(Foo<N> * foo) { for(uns

在外部API中,我定义了结构:
Foo1
Foo4
Foo8
Foo16

现在我需要定义四个函数:

void bar(Foo1*);
void bar(Foo4*);
void bar(Foo8*);
void bar(Foo16*);
这些函数在循环中重复1、4、8和16次执行相同的操作

为了避免编写这些函数4次,我很乐意使用一个模板来定义它们:

template<unsigned int N> void bar(Foo<N> * foo)
{
    for(unsigned int i=0;i<N;++i)
    {
        //Some critical code that optimizes nicely with SSE, AVX, etc...
    }
}
这在功能上与我想要实现的功能相同,但在某种程度上增加了
bar
code,它将充满
foo.f
s,并且依赖于从
FooN*
foo*
的转换

我不知道如何定义模板类Foo,使其专用于Foo1、Foo4、Foo8、Foo16

像这样:

template <int N> struct Foo_impl {};
template <> struct Foo_impl<1 > {using type = Foo1 ;};
template <> struct Foo_impl<4 > {using type = Foo4 ;};
template <> struct Foo_impl<8 > {using type = Foo8 ;};
template <> struct Foo_impl<16> {using type = Foo16;};
template <int N> using Foo = typename Foo_impl<N>::type;

在这里,
throw“Invalid T.”
实际上并不会在运行时抛出,但如果
T
不是
Foo#

中的一个,则会导致编译时错误。对于运行循环,根据类的不同,可以使用从C++11开始的常量表达式:

template<typename T>
void bar(T) {
    constexpr unsigned int N = std::is_same<T, Foo4>::value * 4 + std::is_same<T, Foo16>::value * 16; // likewise for Foo1, Foo8
    // ...
}
将这四个类放在一起如下所示:

template <typename T> void bar(T *foo)
{
    constexpr int N =
        std::is_same_v<T, Foo1 > ? 1  :
        std::is_same_v<T, Foo4 > ? 4  :
        std::is_same_v<T, Foo8 > ? 8  :
        std::is_same_v<T, Foo16> ? 16 : throw "Invalid T.";
    // ...
}
template<typename T>
void bar(T *a) {
    constexpr unsigned int N = std::is_same<T, Foo1>::value * 1
        + std::is_same<T, Foo4>::value * 4
        + std::is_same<T, Foo8>::value * 8
        + std::is_same<T, Foo16>::value * 16;
    static_assert(N > 0, "bar() called with object of invalid type");

    for( unsigned int i = 0; i < N; ++i) {
        std::cout << i << std::endl;
    }
}

这将使用返回类型使函数仅在使用允许的类型(Foo4或Foo16)实例化时编译。从C++17开始,您也可以使用。

这样的东西怎么样?专门化函数,而不是类型本身:

template<typename FooT, unsigned N>
void bar_impl(FooT f)
{
    for (unsigned int i = 0; i < N; ++i)
    {
        //Do magic!
    }
}

template<typename FooT>
void bar(FooT f);

template<>
void bar<Foo1>(Foo1 f)
{
    bar_impl<Foo1, 1>(f);
}
template<>
void bar<Foo4>(Foo4 f)
{
    bar_impl<Foo4, 4>(f);
}
template<>
void bar<Foo8>(Foo8 f)
{
    bar_impl<Foo8, 8>(f);
}
template<>
void bar<Foo16>(Foo16 f)
{
    bar_impl<Foo16, 16>(f);
}
模板
空心钢筋(英尺f)
{
for(无符号整数i=0;i
您可以使用一个helper结构
bar\u trait
,您专门为每种类型
Foo1
Foo4
。然后,这些专门化可以保存各种值,您可以在
bar
函数中使用这些值来控制代码流

这样,
bar
就可以接受您为其创建了
bar\u trait
专门化并支持您在
bar
中对其应用的表达式的任何类型

这样做的好处是:

  • 可以在编译时进行计算,并且不会出现运行时错误
  • 您可以专门化
    bar\u trait
    ,而无需触摸
    bar
  • 您可以在其他可能需要知道
    FooN
    大小的地方重复使用
    bar\u trait
    ,从而减少代码重复
  • 对marcos没有要求
  • 模板参数演绎很有效
structfoo1{};
结构Foo4{};
结构Foo8{};
结构Foo16{};
//为bar_trait创建声明,但不创建定义,以便需要专门化
模板
结构条性状;
//为'Foo1','Foo4',创建专门化…
模板
结构条特征{
静态constexpr const size\u t size=1;
};
模板
结构条特征{
静态constexpr const size\u t size=4;
};
模板
结构条特征{
静态constexpr const size\u t size=8;
};
模板
结构条特征{
静态constexpr const size\u t size=16;
};
//只要存在“bar_trait”的专门化,就接受T的任何类型
//应用于“foo”的表达式是有效的
模板空心条(T*foo)
{
constexpr const auto N=bar\u trait::size;

对于(unsigned int i=0;i您可以声明以下方便类模板,
Foo\u number\u taker

template<typename> struct Foo_number_taker;
您可以很容易地将上面的
Foo\u number\u taker
类模板专门化为
Foo1
Foo4
Foo8
Foo16

DEF_FOO_NUMBER_TAKER(1)
DEF_FOO_NUMBER_TAKER(4)
DEF_FOO_NUMBER_TAKER(8)
DEF_FOO_NUMBER_TAKER(16)
例如,
DEF_FOO_NUMBER_TAKER(8)
将扩展到:

template<> struct Foo_number_taker<Foo8> { static constexpr unsigned value = 8; };
最后,定义
bar()
函数模板,以利用上述变量模板找出与模板参数
FooN
关联的编号:

template<typename FooN>
void bar(FooN* foo) {
   auto constexpr N = Foo_number_v<FooN>;

   for(unsigned i = 0; i < N; ++i) {
      // ...
   }
}

感谢所有的答案!我学到了很多东西。
struct Foo1 {};
struct Foo4 {};
struct Foo8 {};
struct Foo16 {};

// create a declaration for bar_trait but no definition so that specializations are required
template<typename T>
struct bar_trait;

// create the specializations for `Foo1`, `Foo4`, …
template<>
struct bar_trait<Foo1> {
    static constexpr const size_t size = 1;
};

template<>
struct bar_trait<Foo4> {
    static constexpr const size_t size = 4;
};

template<>
struct bar_trait<Foo8> {
    static constexpr const size_t size = 8;
};

template<>
struct bar_trait<Foo16> {
    static constexpr const size_t size = 16;
};

// accepts any type for T as long as a specialization for `bar_trait<T>` exists
// and the expressions applied on `foo` are valid
template<typename T> void bar(T * foo)
{
    constexpr const auto N = bar_trait<T>::size;

    for(unsigned int i=0;i<N;++i)
    {
        //Some critical code that optimizes nicely with SSE, AVX, etc...
    }
}

int main()
{
   Foo1 foo1;
   Foo4 foo4;

   bar(&foo1);
   bar(&foo4);
}
template<typename> struct Foo_number_taker;
#define DEF_FOO_NUMBER_TAKER(N) template<> \
                                struct Foo_number_taker<Foo##N> { \
                                   static constexpr unsigned value = N; \
                                }; 
DEF_FOO_NUMBER_TAKER(1)
DEF_FOO_NUMBER_TAKER(4)
DEF_FOO_NUMBER_TAKER(8)
DEF_FOO_NUMBER_TAKER(16)
template<> struct Foo_number_taker<Foo8> { static constexpr unsigned value = 8; };
template<typename FooN>
static auto constexpr Foo_number_v = Foo_number_taker<FooN>::value;
template<typename FooN>
void bar(FooN* foo) {
   auto constexpr N = Foo_number_v<FooN>;

   for(unsigned i = 0; i < N; ++i) {
      // ...
   }
}
auto main() -> int {
   Foo1 *f1;
   Foo4 *f4;

   // ...

   bar(f1);
   bar(f4);
}