如何让编译器为模板化的get函数推导出正确的返回类型?

时间:2018-02-19 18:26:30

标签: c++ templates

我有一堆结构,都有一些元素:

struct myExample
{
    std::string elem0;
    int elem1;
};

如果我能够完成以下工作,我可以避免大量编码。 编写一个模板化的get方法,它将索引作为模板参数,并从上面的结构中返回elem。

template<int idx, typename K, typename T> T get(const K&) 
{ 
    throw std::runtime_error("should not happen");
}
template<> std::string get<0, myExample, std::string>(const myExample& k)
{
    return k.elem0;
}
template<> int get<1, myExample, int>(const myExample& k)
{
    return k.elem1;
}

以下是该示例的主要功能:

int main() 
{
    myExample test;
    test.elem0 = "hello world";
    test.elem1 = 42;

    // does not work:
    //std::string get0 = ::get<0>(test);
    //int get1 = ::get<1>(test);

    // does not work either:
    //std::string get0 = ::get<0, myExample>(test);
    //int get1 = ::get<1, myExample>(test);

    // works:
    std::string get0 = ::get<0, myExample, std::string>(test);
    int get1 = ::get<1, myExample, int>(test);

    std::cout<<get0<<":"<<get1<<std::endl;
    return 0;
}

我想使用::get<0>(test),但出于某种原因,编译器抱怨没有匹配函数来调用'get(myExample&amp;)' 即使至少模板化的函数抛出错误也应该可用,对吗?

原则上应该可以告诉编译器正确的返回类型,因为elem0和elem1的类型是在编译时定义的。

如何扩展这个类似于元组的结构以返回正确的类型而不必手动写出来?

到目前为止,这适用于较旧的C ++版本,这就是我不应该使用汽车之类的原因。有没有办法让它在没有C ++ 11的情况下工作?

Please check out the example on ideone

非常感谢您的投入!

3 个答案:

答案 0 :(得分:3)

编译器必须在考虑专业化之前推导出所有模板参数,并且无法以这种方式推导T

完全删除typename T参数,不需要它。

您可能还想考虑一个更容易的选择:

template <int Index, typename T> auto get(const T &object)
{
    return std::get<Index>(std::tie(object.elem0, object.elem1, object.elem2));
}

答案 1 :(得分:1)

我认为你有一个小错字,可能会让编译器试图解决模板混乱。在这两行中:

template<> int get<2, myExample, int>(const myExample& k) { return k.elem1_; }
template<> boost::gregorian::date get<2, myExample, boost::gregorian::date>(const myExample& k) { return k.elem2_; }

两个模板都有相同的索引,2。我认为你的int专业化意味着1。

所以我想在索引2的某些场景中,编译器无法在int和日期之间做出决定。

答案 2 :(得分:1)

不要使用模板功能专业化,这几乎总是一个坏主意。

而是使用重载和转发。

template<int idx>
using index_t = std::integral_constant<int, idx>;

// compile time error if it doesn't match
template<int i, class K>
void special_get(index_t<i>, const K&) = delete;

template<int idx, typename K> 
decltype(special_get( index_t<idx>{}, std::declval<K const&>() ) )
get(const K& k) { 
  return special_get( index_t<idx>{}, k );
}

没有专业化。

inline std::string special_get(index_t<0>, const myExample& k) {
  return k.elem0;
}
inline int special_get(index_t<1>, const myExample& k) {
  return k.elem1;
}

这些是special_get的重载。选择哪一个是通过重载决策选择的,而不是模板专业化。

模板功能的专业化不应成为解决任何问题的第一,第二或第三选择。