繁体   English   中英

专门从可变参数模板类中获取函数

[英]Specializing a function from a variadic template class

考虑这个非法代码:

template <int... Is>
struct Object {
    void foo() const;    
};

template <int... Js>
void Object<0, Js...>::foo() {/*Do whatever*/}

我们想在第一个模板参数为0时专门化foo(),并且假设我们想要专门化foo(),如果第二个参数是3,第三个int是1.所以我找到的解决方案(不确定是否它是最好的方法)如下:

#include <iostream>

template <int...> struct Foo;

template <int... Is>
struct Object {
    int ID;  // This member is just to illustrate the case when 'this' is needed in foo().
    friend struct Foo<Is...>;
    void foo() const {Foo<Is...>::execute(this);}  // Pass 'this' in case it is needed.
};

template <int... Is>
struct Foo<0, Is...> {
    static void execute (const Object<0, Is...>* object) {std::cout << "First int = 0, ID = " << object->ID << ".\n";}
};

template <int N, int... Is>
struct Foo<N, 3, Is...> {
    static void execute (const Object<N, 3, Is...>* object) {std::cout << "Second int = 3, ID = " << object->ID << ".\n";}
};

template <int M, int N, int... Is>
struct Foo<M, N, 1, Is...> {
    static void execute (const Object<M, N, 1, Is...>* object) {std::cout << "Third int = 1, ID = " << object->ID << ".\n";}
};


int main() {
    Object<0,5,8,2>{4}.foo();
    Object<4,3,2,5,3>{2}.foo();
    Object<4,2,1>{0}.foo();
}

首先,这个解决方案有什么好处吗? 接下来,如果我们尝试Object<0,3,1,4>{8}.foo(); 因为规格不完整。 因此,让我们说最早匹配的专业int将始终优先。 所以在这种情况下Object<0,3,1,4>{8}.foo(); 应该运行第一个特化因为0,而Object<9,3,1,4>{8}.foo(); 由于3,所以应该进行第二次专业化,依此类推。 如何执行该规则?

评论和提示。

我的方法还可以。 由于我们没有对所有功能进行部分模板专业化。

然后关于Object<0,3,1,4>{8}.foo()这给出了模糊的部分特化(在Clang 3.6上)。 为了解决这个问题,我最后添加了另一个部分特化

template <int... Is>
struct Foo<0, 3, Is...> {
    static void execute (const Object<0, 3, Is...>* object) {std::cout << "First int = 0, second = 3, ID = " << object->ID << ".\n";}
};

另一种可能性是使用std :: integer_sequence。 我现在必须放弃,以下不是解决方案,只是一个开胃菜......

#include <utility>
#include <iostream>

template <class S1, class S2>
struct seq_lt
{
    enum {value = 0} ;
} ;

template <int I1, int ...S1, int I2, int ...S2>
struct seq_lt<std::integer_sequence<int, I1, S1...>,
              std::integer_sequence<int, I2, S2...>>
{
    enum {value = (I1 < I2 ? 1 : 0)} ;
} ;


int main(int argc, char *argv[])
{
    std::integer_sequence<int, 1, 2, 3> seq1 ;
    std::integer_sequence<int, 2, 3> seq2 ;

    std::cout << "seq_lt " << seq_lt<decltype(seq1), decltype(seq2)>::value << std::endl ;
    std::cout << "seq_lt " << seq_lt<decltype(seq2), decltype(seq1)>::value << std::endl ;
}

我建议只使用if语句。 无论如何,编译器可能会优化它们(假设您已启用优化)。

换句话说,只需做这样的事情:

template <int... Js>
void Object::foo() {
    std::array<int, sizeof...(Js)> args = {Js...}; // I _think_ this is the correct syntax to dump the parameter pack into an std::array.
    if(args.size() > 0 && args[0] == 0) {
        // First argument is 0, do whatever.
    } else {
        // It's not 0, do your other thing.
    }
}

你会得到几乎相同的效果,你的代码会更加清晰。

这个解决方案的灵感来自于Marom的第二个建议,也部分受到了celticminstrel解决方案的启发。

#include <iostream>
#include <type_traits>

template <std::size_t, typename T, T...> struct NthValue;

template <typename T, T First, T... Rest>
struct NthValue<0, T, First, Rest...> : std::integral_constant<T, First> {};

template <std::size_t N, typename T, T First, T... Rest>
struct NthValue<N, T, First, Rest...> : NthValue<N - 1, T, Rest...> {};

template <int... Is>
struct Object {
    void foo() const {fooHelper (typename Map<Is...>::type{});}
private:
    template <int...> struct Map;
    template <int, int> struct MappedType {};
    struct Default {};
    void fooHelper (const MappedType<0,0>&) const {std::cout << "First int = 0.\n";}
    void fooHelper (const MappedType<1,3>&) const {std::cout << "Second int = 3.\n";}
    void fooHelper (const MappedType<2,1>&) const {std::cout << "Third int = 1.\n";}
    void fooHelper (const Default&) const {std::cout << "Default case.\n";}
};

template <int... Ns>
template <int... Is>
struct Object<Ns...>::Map {
    using type = typename std::conditional<NthValue<0, int, Is...>::value == 0,
        MappedType<0,0>, 
        typename std::conditional<NthValue<1, int, Is...>::value == 3,
            MappedType<1,3>,
            typename std::conditional<NthValue<2, int, Is...>::value == 1,
                MappedType<2,1>,
                Default
            >::type
        >::type
    >::type;
};

int main() {
    Object<0,5,8,2>().foo();  // First int = 0.
    Object<4,3,2,5,3>().foo();  // Second int = 3.
    Object<4,2,1>().foo();  // Third int = 1.
    Object<0,3,1,4>().foo();  // First int = 0.
    Object<9,3,1,4>().foo();  // Second int = 3.
    Object<9,9,9>().foo();  // Default case.
}

也没有运行时开销。

暂无
暂无

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

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