递归模板函数不能用Clang编译?

时间:2017-02-10 14:05:50

标签: g++ clang c++14

我有一个模板函数,可以通过参数包进行递归。本质上,它旨在将something.Get<A,B,C>()映射到something.Get<A>().Get<B>().Get<C>()

这可以通过(完全独立的源码)来实现

template <typename... Pack> class Struct {
  std::tuple<Pack...> mTuple;
  template <typename Type> auto &GetRef_internal() {
    return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
        mTuple);
  }
public:
  template <typename Current> Current &GetRef() {
    return GetRef_internal<Current>();
  }
  template <typename Current, typename... Next,
            typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr>
  auto &GetRef() {
    auto current = GetRef_internal<Current>();
    return current.GetRef<Next...>();
  }
};

其中first_true返回第一个元素的索引为真。

这用g ++编译,似乎在MSVC上使用online compiler编译。使用clang ++进行编译时,我得到以下错误:

test.cxx:40:31: error: expected '(' for function-style cast or type construction
    return current.GetRef<Next...>();
                          ~~~~^
test.cxx:38:9: error: cannot deduce return type 'auto &' for function with no return statements
  auto &GetRef() {
        ^
test.cxx:48:12: note: in instantiation of function template specialization 'Struct<Struct<int, Struct<float, float> >, Struct<char>, int>::GetRef<Struct<int, Struct<float, float> >, Struct<float, float> , nullptr>' requested here
          .GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>();
           ^
2 errors generated.

是什么导致这种情况?

P.S。实际的生产代码&#39;比示例看起来更有用,但是这里发布的内容太多了。

=============================================== ==========================

#include <tuple>
#include <type_traits>

// Template to check if condition holds true for all members of a parameter
// pack.
template <bool... b> struct BoolArray {};
template <bool... b>
using all_true = std::is_same<BoolArray<b...>, BoolArray<(b, true)...>>;

//helper type trait
template <bool... b> struct first_true {
  template <
      unsigned index = 0,
      typename std::enable_if<index<sizeof...(b)-1>::type * =
                                  nullptr> static constexpr unsigned check() {
    return std::get<index>(std::make_tuple(b...)) ? index : check<index + 1>();
  }
  template <unsigned index = 0,
            typename std::enable_if<index >= sizeof...(b)-1>::type * = nullptr>
  static constexpr unsigned check() {
    return std::get<index>(std::make_tuple(b...)) ? index : 0;
  }
  static constexpr unsigned value = first_true<b...>::check();
};

//The actual problem struct
template <typename... Pack> class Struct {
  std::tuple<Pack...> mTuple;
  template <typename Type> auto &GetRef_internal() {
    return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
        mTuple);
  }
public:
  template <typename Current> Current &GetRef() {
    return GetRef_internal<Current>();
  }
  template <typename Current, typename... Next,
            typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr>
  auto &GetRef() {
    auto current = GetRef_internal<Current>();
    return current.GetRef<Next...>();
  }
};

int main() {
  // Define a random nested struct
  Struct<Struct<int, Struct<float, float>>, Struct<char>, int> myStruct;
  // Then retrieve one of the substructures to instantiate the template
  auto substruct =
      myStruct
          .GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>();
 return 0;
}

1 个答案:

答案 0 :(得分:0)

current.GetRef<Next...>是从属名称,因此您需要使用GetRef关键字指定template为模板命名:

return current.template GetRef<Next...>();

有关从属名称的详细信息,请参阅Where and why do I have to put the "template" and "typename" keywords?