0

我需要一种特殊的可变参数容器并且遇到了一些无法预料的问题,因此我创建了以下最小示例(请参阅注释):

#include <iostream>
#include <tuple>

//---------------------------------------------------
template<class...Ts>
class container
{
    using ts_type = std::tuple<Ts...>;

public:
    container() = default;

    container(Ts... ts) : ts_{std::move(ts)...} {}

    // get #1: member template
    template<std::size_t index>
    auto 
    get() const -> decltype(std::get<index>(std::declval<const ts_type>())) {
        return std::get<index>(ts_);
    }

    // get #2: friend function
    template<std::size_t index>
    friend typename std::tuple_element<index,ts_type>::type
    get(const container& c) {
        return std::get<index>(c.ts_);
    }

    // get #3: friend function with type deduction
    // won't compile 
    // error: 'const class container<int, double>' has no member named 'ts_'
    //
    // template<std::size_t index>
    // friend auto 
    // get(const container& c) -> decltype(std::get<index>(c.ts_)) {
    //  return std::get<index>(c.ts_);
    // }


private:
    ts_type ts_;
};

//---------------------------------------------------
// WTF? g++ already complains about the declaration
// I'm not even trying to instantiate foo
template<class T>
void foo(const T& t) {
    // error: expected primary-expression before ')' token
    std::cout << t.get<0>() << std::endl;

    // error: 'get' was not declared in this scope
    std::cout << get<0>(t) << std::endl;
}

//---------------------------------------------------
int main() {   
    // this compiles and runs just fine ... as expected
    auto c = container<int,double>{1, 2.5};

    std::cout << c.get<0>() << std::endl;
    std::cout << c.get<1>() << std::endl;

    std::cout << get<0>(c) << std::endl;
    std::cout << get<1>(c) << std::endl;
}

这里发生了什么?为什么 g++ (4.7.2) 抱怨 foo 中的声明?为什么 container::get #3 不能编译?
我猜像 get<0> 这样的东西只能在具体类型上调用?
这个行为标准符合吗?

4

2 回答 2

0

好的,现在可以了!谢谢您的帮助!

#include <iostream>
#include <tuple>

//---------------------------------------------------
template<class...Ts>
class container
{
    using ts_type = std::tuple<Ts...>;

public:
    container() = default;

    container(Ts... ts) : ts_{std::move(ts)...} {}

    template<std::size_t index>
    auto 
    get() const -> decltype(std::get<index>(std::declval<const ts_type>())) {
        return std::get<index>(ts_);
    }

    template<std::size_t index, class... Us>
    friend auto 
    get(const container<Us...>& c) -> decltype(std::get<index>(c.ts_));

private:
    ts_type ts_;
};


template<std::size_t index, class... Us>
auto get(const container<Us...>& c) -> decltype(std::get<index>(c.ts_)) {
    return std::get<index>(c.ts_);
}


//---------------------------------------------------
template<class T>
void foo(const T& t) {
    std::cout << t.template get<0>() << std::endl;

    std::cout << get<0>(t) << std::endl;
}

//---------------------------------------------------
int main() {   
    auto c = container<int,double>{1, 2.5};

    std::cout << c.get<0>() << std::endl;
    std::cout << c.get<1>() << std::endl;

    std::cout << get<0>(c) << std::endl;
    std::cout << get<1>(c) << std::endl;

    foo(c);
}
于 2014-05-12T21:11:29.567 回答
0

您有一个可修复的问题和一个不可修复的问题:

foo你需要告诉编译器你正在调用一个模板: std::cout << t.template get<0>() << std::endl;

同样在foo独立功能中get取决于容器的实例化,这在使用时不可用(您之前可能会显式实例化容器,但我认为这无法解决)。

另一个问题是注释代码(#3)。在这里,我将ts_type ts_作为公共成员放在前面get(const container& c) -> decltype(std::get<index>(c.ts_)),但这并不能回答这个问题。

于 2014-05-12T20:36:03.140 回答