getter到variadic容器 - 得到< 0>()只处理具体类型?

时间:2014-05-12 20:16:55

标签: c++ templates stdtuple

我需要一种特殊的可变容器并且有一些不可预知的问题,所以我创建了以下最小的例子(见注释):

#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&lt; 0&gt;这样的东西只能在具体类型上调用?
这种行为符合标准吗?

2 个答案:

答案 0 :(得分: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_))前面,但这并没有回答这个问题。

答案 1 :(得分: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);
}