Meta-Programming with a Method Parameter

2019-08-11 13:44发布

I'm writing a pair wrapper. For the purposes of this question it can be simplified down to:

using namespace std;

template <class T1, class T2>
class myPair {
    pair<T1, T2> member;
public:
    myPair() = default;
    myPair(T1 x, T2 y) : member(make_pair(x, y)) {}
};

I'd like to be able to treat a myPair as an index-able container of size 2. To do this I'd obviously need to write an index operator for myPair. I'd like to do something like this, but my return type will depend upon a method parameter, and I can't use method parameters in meta-programming.

auto myPair::operator[](int index) {
    static_assert(index >= 0 && index < 2, "Index out of range");

    return get<index>(*this);
}

Obviously I could tackle this in the same way that pair does by providing a get function, but I'd like to me able to use the index operator syntax. Is there any way I can specialize a function template or use a method parameter to meta-program a template's return type?

3条回答
放荡不羁爱自由
2楼-- · 2019-08-11 14:22

No, it's not possible. The member function operator[] accepts non-constexpr objects, therefore making a compile time type detection pretty much impossible.

This will also make the static_assert not compile, for the same reason.

查看更多
冷血范
3楼-- · 2019-08-11 14:33

You may use std::intergral_constant

template <std::size_t N>
const auto& operator[](std::integral_constant<std::size_t, N>) const {
    static_assert(N < 2, "Index out of range");

    return std::get<N>(member);
}

template <std::size_t N>
auto& operator[](std::integral_constant<std::size_t, N>) {
    static_assert(N < 2, "Index out of range");

    return std::get<N>(member);
}

Live Demo

查看更多
SAY GOODBYE
4楼-- · 2019-08-11 14:45

It's almost possible. The integer literal can't be used directly as a constant-expression, but it can be wrapped in one, for example a template instantiation.

template <int> struct idx_ {};

template <char... C>
auto operator ""_i () {
    return idx_<(C - '0')...>{};
}

template <class T1, class T2>
class myPair {
    std::pair<T1, T2> member;
public:
    myPair() = default;
    myPair(T1 x, T2 y) : member(std::make_pair(x, y)) {}

    T1 &operator [] (idx_<0>) {
        return member.first;
    }

    T2 &operator [] (idx_<1>) {
        return member.second;
    }
};

int main() {
    myPair<int, std::string> mp(42, "Hi");
    std::cout << mp[0_i] << ", " << mp[1_i] << '\n';
}

Output:

42, Hi

Live on Coliru

查看更多
登录 后发表回答