【问题标题】:Meta-Programming with a Method Parameter带有方法参数的元编程
【发布时间】:2015-08-10 14:20:07
【问题描述】:

我正在写一个pair 包装器。就这个问题而言,它可以简化为:

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)) {}
};

我希望能够将myPair 视为大小为2 的可索引容器。为此,我显然需要为myPair 编写索引运算符。我想做这样的事情,但是我的返回类型将取决于方法参数,并且我不能在元编程中使用方法参数。

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

    return get<index>(*this);
}

显然,我可以像pair 一样通过提供get 函数来解决这个问题,但我希望能够使用索引运算符语法。有什么方法可以专门化函数模板或使用方法参数对模板的返回类型进行元编程?

【问题讨论】:

  • std::get 有什么问题?
  • @CoffeeandCode get 没有什么问题,但这意味着一个pair 不能像另一个容器一样被索引。
  • @JonathanMee pairstuples 在 C++StdLib 的概念意义上不是容器。大写 C Container 是同构容器,即它的所有元素都具有相同的类型。从语法上讲,您到底想达到什么目的? (包括您希望如何使用返回值。)
  • 有 3 种方法可以解决这个问题。首先,延续传递风格(你采取延续,并将返回值传递给它)。其次,返回一个多态的可访问值(如boost::variant),类似。最后,将索引存储在参数的类型中。它们都不是您想要的:运行时值不能用于更改 C++ 中表达式的静态类型,静态类型是编译时已知的(子集)。
  • @dyp 我正在尝试通过调用get 来实现相同的目标,但是myPair 将被传递到模板化函数中,因此我需要它的行为与其他函数一样索引可访问的容器。模板化函数将仅访问容器的一个元素。将此结果分配给const auto 变量并处理该变量。模板化函数在 get 上工作得很好,只是我必须专门化它,我不想这样做。

标签: c++ templates indexing return-type std-pair


【解决方案1】:

几乎是可能的。整数文字不能直接用作常量表达式,但它可以包装在一个中,例如模板实例化。

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';
}

输出:

42, Hi

Live on Coliru

【讨论】:

  • @dyp 我曾考虑过,并说服自己这是不可能的。感谢您的疑问:p
  • Boost.hana 还包含一个实现:ldionne.com/hana/…
  • @dyp 我的意思是我再试一次,成功了:)
  • 天啊!我没有注意到你改变了答案!
  • @Quentin 这是一个非常有创意的解决方案,但仍然不是完全我所希望的,因为我仍然无法像常规容器那样进行索引。
【解决方案2】:

不,这是不可能的。成员函数 operator[] 接受非 constexpr 对象,因此几乎不可能进行编译时类型检测。

这也将使static_assert 无法编译,原因相同。

【讨论】:

    【解决方案3】:

    您可以使用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

    【讨论】:

    • 一些我不明白的辉煌?当我尝试将此添加为myPair 的方法时,我得到:“错误 C2784:'auto &myPair::operator [](std::integral_constant)': 无法推断模板来自 'size_t' 的 'std::integral_constant' 的参数”我用错了吗?
    • 刚刚添加了一个现场演示。 (实际上它是 Quentin 解决方案的一种变体)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 1970-01-01
    • 2021-10-26
    • 2013-03-08
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多