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

时间:2015-07-08 05:41:07

标签: c++ templates c++11 specialization

考虑这个非法代码:

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

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

当第一个模板参数为0时,我们想要专门化foo(),并且如果第二个参数是3,那么我们想要专门化foo(),第三个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,依此类推。如何执行该规则?

3 个答案:

答案 0 :(得分:1)

评论和提示。

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

然后关于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 ;
}

答案 1 :(得分:1)

我建议只使用error Error: No compatible version found: bower-endpoint-parser@'^0.2.2' 1073 error Valid install targets: 1073 error ["0.1.0-rc.1","0.1.0","0.2.0","0.2.1","0.2.2"] 1073 error at installTargetsError (C:\Users\myname\node-0.10.4\node-0.10.4\node_modules\npm\lib\cache.js:685:10) 1073 error at C:\Users\myname\node-0.10.4\node-0.10.4\node_modules\npm\lib\cache.js:607:10 1073 error at saved (C:\Users\myname\node-0.10.4\node-0.10.4\node_modules\npm\node_modules\npm-registry-client\lib\get.js:138:7) 1073 error at Object.oncomplete (fs.js:107:15) 1074 error If you need help, you may report this log at: 1074 error <http://github.com/isaacs/npm/issues> 1074 error or email it to: 1074 error <npm-@googlegroups.com> 1075 error System Windows_NT 6.1.7601 1076 error command "C:\\Users\\myname\\node-0.10.4\\node-0.10.4\\\\node.exe" "C:\\Users\\myname\\node-0.10.4\\node-0.10.4\\node_modules\\npm\\bin\\npm-cli.js" "install" "bower" 1077 error cwd C:\Users\myname\BowerJS 1078 error node -v v0.10.4 1079 error npm -v 1.2.18 语句。无论如何,编译器可能会优化它们(假设您已启用优化)。

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

if

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

答案 2 :(得分:1)

这个解决方案的灵感来自于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.
}

也没有运行时开销。