简体   繁体   中英

C++ template specialized getters

I am currently writing a program working with NURBS surfaces , where you can perform algorithms in two directions ( U and V ). To avoid code duplication I tried to use templates, but I am by no means experienced using them. Here is a small example of what I would like to do:

#include <iostream>

enum class Dir {
    U, V
};

struct Foo {

    unsigned cu, cv;

    Foo(unsigned cu, unsigned cv) : cu(cu), cv(cv) {};

    template<Dir>
    const Dir otherDir();

    template<>
    const Dir otherDir<Dir::V>() {
        return Dir::U;
    }

    template<>
    const Dir otherDir<Dir::U>() {
        return Dir::V;
    }

    template<Dir>
    unsigned count();

    template<>
    unsigned count<Dir::U>() {
        return cu;
    }

    template<>
    unsigned count<Dir::V>() {
        return cv;
    }

    template<Dir d>
    unsigned totalCount() {
        auto c = count<d>();
        auto cOther = count<otherDir<d>()>();
        return c * cOther;
    }

};

int main() {
    Foo f(3,2);
    std::cout << (f.count<Dir::U>() == 3) << std::endl;
    std::cout << (f.otherDir<Dir::U>() == Dir::V) << std::endl;
    std::cout << f.totalCount<Dir::U>() << std::endl;
}

but this doesn't compile due to the last line in main (VS2015, but I don't think it's compiler's fault):

1>...\main.cpp(42): error C2672: 'Foo::count': no matching overloaded function found
1>...\main.cpp(52): note: see reference to function template instantiation 'unsigned int Foo::totalCount<Dir::U>(void)' being compiled
1>...\main.cpp(42): error C2975: 'unnamed-parameter': invalid template argument for 'Foo::count', expected compile-time constant expression
1>...\main.cpp(27): note: see declaration of 'unnamed-parameter'
1>...\main.cpp(43): error C3536: 'cOther': cannot be used before it is initialized

Only way I got close to the functionality above is by specifying both the main direction as well as the other direction as the template arguments like this:

struct Foo {

    ...

    template<Dir d, Dir otherD>
    unsigned totalCount() {
        auto c = count<d>();
        auto cOther = count<otherD>();
        return c * cOther;
    }

};

int main() {
    Foo f(3,2);
    std::cout << f.totalCount<Dir::U, Dir::V>() << std::endl;
}

but that doesn't seem to be very elegant.

Probably, problem is here:

auto cOther = count<otherDir<d>()>();

Templates are "resolved" in compile time. You should use constexpr for otherDir<d>() because just simple const doesn't mean that method can be evaluated in compile time.

More traditional approach is to have structure otherDir instead of method. Create structure template, two instantiations would be with static const value = V or U .

Or you can replace enum with empty structs.

Or, what's even better, you can try to implement it without templates and create class for dimension and have one object per each dimension.

otherDir<d>() is not constexpr , and cannot be used in template argument ( count<otherDir<d>()>() ).

You may add constexpr (and static ) to that method, or use old struct to handle that:

template <Dir> struct otherDir;

template<>
struct otherDir<Dir::U>
{
    static constexpr Dir value = Dir::V;
};

template<>
struct otherDir<Dir::V>
{
    static constexpr Dir value = Dir::U;
};

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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