我需要一种特殊的可变参数容器并且遇到了一些无法预料的问题,因此我创建了以下最小示例(请参阅注释):
#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> 这样的东西只能在具体类型上调用?
这个行为标准符合吗?