具有常量值的 C++ 模板特化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4840819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:43:04  来源:igfitidea点击:

C++ Template Specialization with Constant Value

c++templatestemplate-specialization

提问by tadman

Is there a straightforward way for defining a partial specialization of a C++ template class given a numerical constant for one of the template parameters? I'm trying to create special constructors for only certain kinds of template combinations:

给定一个模板参数的数值常量,是否有一种直接的方法来定义 C++ 模板类的部分特化?我正在尝试为某些类型的模板组合创建特殊的构造函数:

template <typename A, size_t B> class Example
{
    public:
        Example() { };

        A value[B];
};

template <typename A, 2> class Example
{
    public:
        Example(b1, b2) { value[0] = b1; value[1] = b2; };
};

This example won't compile, returning an error Expected identifier before numeric constantin the second definition.

这个例子不会编译,Expected identifier before numeric constant在第二个定义中返回一个错误。

I've had a look through a number of examples here and elsewhere, but most seem to revolve around specializing with a type and not with a constant.

我已经看过这里和其他地方的一些例子,但大多数似乎都围绕着专门研究类型而不是常数。

Edit:

编辑:

Looking for a way to write a conditionally used constructor, something functionally like this:

寻找一种方法来编写有条件使用的构造函数,其功能如下:

template <typename A, size_t B> class Example
{
    public:
        // Default constructor
        Example() { };

        // Specialized constructor for two values
        Example<A,2>(A b1, A b2) { value[0] = b1; value[1] = b2; };

        A foo() {
          A r;

          for (size_t i = 0; i < b; ++b)
            r += value[i];

          return r;
        }

        // Hypothetical specialized implementation
        A foo<A, 2>() {
          return value[0] + value[1];
        }

        A value[B];
};

采纳答案by Marlon

I think this might work:

我认为这可能有效:

#include <iostream>

template <typename A, size_t B>
class Example {
public:
    Example()
    {
        Construct<B>(identity<A, B>());
    }

    A foo()
    {
        return foo<B>(identity<A, B>());
    }

private:
    template <typename A, size_t B>
    struct identity {};

    template <size_t B>
    void Construct(identity<A, B> id)
    {
        for (size_t i = 0; i < B; ++i)
        {
            value[i] = 0;
        }
        std::cout << "default constructor\n";
    }

    template <size_t B>
    void Construct(identity<A, 2> id)
    {
        value[0] = 0;
        value[1] = 0;
        std::cout << "special constructor\n";
    }

    template <size_t B>
    A foo(identity<A, B> id)
    {
        A r = 0;
        for (size_t i = 0; i < B; ++i)
        {
            r += value[i];
        }
        std::cout << "default foo\n";
        return r;
    }

    template <size_t B>
    A foo(identity<A, 2> id)
    {
        std::cout << "special foo\n";
        return value[0] + value[1];
    }

    A value[B];
};

int main()
{
    Example<int, 2> example; // change the 2 to see the difference
    int n = example.foo();
    std::cin.get();
    return 0;
}

Sorry, I just copy and pasted it from my test project. It's not really "specialization" in a way, it just calls overloads to specialized functions. I'm not sure if this is what you want and imo this isn't very elegant.

抱歉,我只是从我的测试项目中复制并粘贴了它。从某种意义上说,它并不是真正的“专业化”,它只是将重载调用到专门的函数。我不确定这是否是您想要的,而且这不是很优雅。

回答by Foo Bah

You need to put the specialization in the correct place:

您需要将专业放在正确的位置:

template <typename A> class Example<A,2>

If you want to create a subclass:

如果要创建子类:

template <typename A> class ExampleSpecialization : public Example<A,2>

The behavior for specializing on typedefs is similar to the behavior for specializing on an integer parameter.

专用于 typedef 的行为类似于专用于整数参数的行为。

回答by Jerry Coffin

If memory serves, it should be more like:

如果没记错的话,应该更像是:

template <typename A, size_t B> class Example
{
    public:
        Example() { };

        A value[B];
};

template <typename A> class Example<A, 2>
{
    public:
        Example(A b1, A b2) { value[0] = b1; value[1] = b2; };
};

I don't think this is quite allowable as-is though -- there's nothing defining the types of b1and/or b2in the specialized version.

我不认为这是完全允许的——虽然没有定义专业版本的类型b1和/或b2

Edit [based on edited question]: Yes, a template specialization produces a new type that's not really related to the base from which it's specialized. In particular, the two do notshare any of the implementation. You can't (by specializing a class template) produce a single type that uses one of two different ctors, depending on the value of a non-type parameter.

编辑 [基于编辑过的问题]:是的,模板特化产生了一种新类型,它与它所特化的基础没有真正的关系。特别是,两者共享任何实现。您不能(通过专门化类模板)生成使用两种不同构造函数之一的单一类型,具体取决于非类型参数的值。

回答by Pawel Zubrycki

You can try something like this:

你可以尝试这样的事情:

template<size_t s>
struct SizeTToType { static const size_t value = s; };

template<bool> struct StaticAssertStruct;
template<> struct StaticAssertStruct<true> {};
#define STATIC_ASSERT(val, msg) { StaticAssertStruct<((val) != 0)> ERROR_##msg; (void)ERROR_##msg;}

template <typename A, size_t B> 
class Example
{
    public:
        Example() { };
        Example(A b1){ value[0] = b1; }
        Example(A b1, A b2) { 
                STATIC_ASSERT(B >= 2, B_must_me_ge_2); 
                value[0] = b1; value[1] = b2;
        } 
        A foo() { return in_foo(SizeTToType<B>()); }
    protected:
        template<size_t C>
        A in_foo(SizeTToType<C>) {
                cout << "univ" << endl;
                A r;
                for (size_t i = 0; i < B; ++i)
                r += value[i];
                return r;
        }
        A in_foo(SizeTToType<2>){
                cout << "spec" << endl;
                return value[0] + value[1];
        }
        A value[B];
};

Working example on http://www.ideone.com/wDcL7

http://www.ideone.com/wDcL7 上的工作示例

In templates if you are not using method it won't exists in compiled code, so this solution shouldn't make executable bigger because of ctors you can't use with some specialized class (for example Example<int, 1>should not have Example(A b1, A b2)ctor).

在模板中,如果您不使用方法,则编译代码中将不存在它,因此该解决方案不应使可执行文件变大,因为您无法将 ctors 与某些专用类一起使用(例如,Example<int, 1>不应具有Example(A b1, A b2)ctor)。

回答by MerickOWA

If you're goal is to only have to override a few methods/constructors in your specializations then maybe consider a generic base class to hold the common implementation for all Exampletemplates so you don't have to rewrite it in every specialization you come up with.

如果您的目标是只需要覆盖专业化中的一些方法/构造函数,那么可以考虑使用通用基类来保存所有Example模板的通用实现,这样您就不必在提出的每个专业化中重写它.

For example:

例如:

template < typename A, size_t B >
class ExampleGeneric {
public:

  // generic implementation of foo inherited by all Example<A,B> classes
  void foo() {
    A r;

    for (size_t i = 0; i < B; ++i)
      r += value[i];

    return r;
    }

  // generic implementation of bar inherited by all Example<A,B> classes
  void bar() {
    A r;

    for (size_t i = 0; i < B; ++i)
      r *= value[i];

    return r;
    }

  A values[B];
  };

template < typename A, size_t B >
class Example : public ExampleGeneric<A,B> {
public:
  //default to generic implementation in the general case by not overriding anything
  };

//*** specialization for 2
template < typename A >
class Example<A,2> : public ExampleGeneric<A,2>{
public:

  // has to be provided if you still want default construction
  Example() {
    }

  //extra constructor for 2 parameters
  Example( A a1, A a2 ) {
    values[0] = a1;
    values[1] = a2;
    }

  // specialization of foo
  void foo() {
    return values[0] + values[1];
    }

  // don't override bar to keep generic version
  };

回答by NoName

#include <iostream>

using namespace std;


template<typename _T, size_t S>
class myclass {
    _T elem[S];
public:
    myclass() {
        for (int i = 0; i < S; i++) {
            elem[i] = i;
        }
    }
    void Print() {
        for (int i = 0; i < S; i++) {
            cout << "elem[" << i << "] = " << elem[i] << endl;
        }
    }
};


int main(int argc, char **argv)
{
    myclass < int, 10 > nums;
    nums.Print();
    myclass < int, 22 > nums1;
    nums1.Print();
}

That worked on my linux machine with

这在我的 linux 机器上工作

g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-48) Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-48) 版权所有 (C) 2006 Free Software Foundation, Inc。这是免费软件;请参阅复制条件的来源。没有保修;甚至不是为了特定目的的适销性或适合性。