简体   繁体   English

根据成员容器的大小专门化成员函数

[英]Specialize member functions based on size of member container

I have a class that holds some statically-sized containers: 我有一个类,它包含一些静态大小的容器:

template <typename Container>
struct Point {
    Container container;
    ... 
    void bar();
}

where a Container class might look like: Container类可能如下所示:

struct Container1 {
    static constexpr size_t size = 5;
}

Now I want to specialize the bar method based on the size of the container. 现在我想根据容器的大小来专门化bar方法。 I do not understand how to do that. 我不明白该怎么做。

EDIT: 编辑:

I would like a C++11 solution. 我想要一个C ++ 11解决方案。 C++14 might work, but the compilers we work with typically have spotty C++14 support. C ++ 14可能有用,但我们使用的编译器通常具有不稳定的C ++ 14支持。

EDIT: 编辑:

Stack Danny suggested a solution which compiles with Clang, but not with GCC. Stack Danny提出了一个解决方案,它与Clang编译,但不与GCC编译。

Instead of specialisation, use SFINAE 而不是专业化,使用SFINAE

template <typename Container>
class Point {
    Container container;
    template<size_t S> std::enable_if_t<S==3>
    bar_t() { std::cout << "specialisation for size=3\n"; }
    template<size_t S> std::enable_if_t<S==5>
    bar_t() { std::cout << "specialisation for size=5\n"; }
    template<size_t S> std::enable_if_t<S==42>
    bar_t() { std::cout << "specialisation for size=42\n"; }
  public:
    void bar()
    { bar_t<Container::size>(); }
};

std::enable_if_t is C++14, but you can trivially declare it yourself: std::enable_if_t是C ++ 14,但你可以自己简单地声明它:

#if __cplusplus < 201402L
template<bool C, typename T=void>
using enable_if_t = typename enable_if<C,T>::type;
#endif

Btw, your question smells like an XY problem : do you really need to specialize bar() for the Container::size ? 顺便说一句,你的问题有点像XY问题 :你真的需要为Container::size专门化bar()吗? In the following example, a loop is unrolled for any size N . 在以下示例中,为任何大小N展开循环。

template<typename scalar, size_t N>
class point // a point in R^N
{
    scalar array[N];
  public:
    // multiplication with scalar
    point& operator*=(scalar x) noexcept
    {
        // unroll loop using template meta programming
        loop([array,x](size_t i) { array[i] *= x; };);
        /* alternatively: rely on the compiler to do it
        for(size_t i=0; i!=N; ++i)
            array[i] *= x;
        */
        return *this;   
    }
  private:
    template<size_t I=0, typename Lambda>
    static enable_if_t<(I<N)> loop(Lambda &&lambda)            
    {
        lambda(I);
        loop<I+1>(lambda);
    }
    template<size_t I=0, typename Lambda>
    static enable_if_t<(I>=N)> loop(Lambda &&)         {}
};

It is called template specialization and works as follows: 它被称为模板专业化,其工作原理如下:

#include <cstdint>
#include <iostream>

struct Container1 {
    static constexpr size_t size = 5;
};
struct Container2 {
    static constexpr size_t size = 3;
};


template <typename Container>
struct Point {
    Container container;

    void bar() {
        this->bar_templated<Container::size>();
    }

private:
    template<std::size_t size>
    void bar_templated() {
        std::cout << "default\n";
    }
    template<>
    void bar_templated<3>() {
        std::cout << "specialized <3>\n";
    }
    template<>
    void bar_templated<5>() {
        std::cout << "specialized <5>\n";
    }
};

int main(){
    Point<Container1> p1;
    p1.bar();
    Point<Container2> p2;
    p2.bar();
}

output 产量

specialized <5>
specialized <3>

due to bug 85282 in gcc making it impossible to compile an explicit specialization in non-namespace scope (thanks @songyuanyao), there are errors: 由于gcc中的bug 85282使得无法在非命名空间范围内编译显式特化 (感谢@songyuanyao),因此存在错误:

25:14: error: explicit specialization in non-namespace scope 'struct Point' 25:14:错误:非命名空间范围'struct Point'中的显式特化

26:27: error: template-id 'bar_templated<3>' in declaration of primary template 26:27:错误:主模板声明中的template-id'bar_templated <3>'

... ...

30:10: error: 'void Point::bar_templated()' cannot be overloaded 30:10:错误:'void Point :: bar_templated()'无法重载

But you can workaround this by moving the functions out of the class and still achieve specialization: 但是你可以通过将函数移出类并仍然实现特化来解决这个问题:

template<std::size_t size>
void bar_templated() {
    std::cout << "default\n";
}
template<>
void bar_templated<3>() {
    std::cout << "specialized 3\n";
}
template<>
void bar_templated<5>() {
    std::cout << "specialized 5\n";
}


template <typename Container>
struct Point {
    Container container;

    void bar() {
        bar_templated<Container::size>();
    }
};

This way the functions are public, which may not be what you want, though. 这样,函数是公共的,但可能不是你想要的。 Well, if you're writing inside a header file you could define them inside an anonymous namespace. 好吧,如果你在头文件中写入,你可以在匿名命名空间内定义它们。


Also: if constexpr - but that's only C++17 and forward. 另外: 如果constexpr - 但那只是C ++ 17和前进。 It reducing the code size by alot and keeping it's logical nature makes it the best approach here, for sure. 它确实减少代码大小并保持其逻辑性质使其成为最佳方法。

void bar() {
    if constexpr (Container::size == 3) {
        std::cout << "specialized <3>\n";
    }
    else if constexpr (Container::size == 5) {
        std::cout << "specialized <5>\n";
    }
}

You can apply template overloading with SFINAE . 您可以使用SFINAE应用模板重载。

template <typename C = Container>
auto bar() -> typename std::enable_if<C::size==5>::type { ... }
template <typename C = Container>
auto bar() -> typename std::enable_if<C::size==42>::type { ... }
... ...

LIVE 生活

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

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