【问题标题】:recursive template function does not compile with Clang?递归模板函数不能用 Clang 编译?
【发布时间】:2017-06-28 22:00:37
【问题描述】:

我有一个在参数包上递归的模板函数。本质上,它意味着将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.

这是什么原因造成的?

附言实际的“生产代码”比示例看起来更有用,但是在这里发布太多了。

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

#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;
}

【问题讨论】:

    标签: g++ clang c++14


    【解决方案1】:

    current.GetRef&lt;Next...&gt; 是从属名称,因此您需要指定 GetRef 使用 template 关键字命名模板:

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

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

    【讨论】:

    • 这成功了!今天学到了新东西。只要它允许我就会接受这个答案。有趣的是,即使使用 -pedantic,g++ 也能解决它。
    • @CodingCat 规范说如果你有“foo.bargcc.gnu.org/bugzilla/show_bug.cgi?id=55576 中的问题。在那个错误报告中,GCC 拒绝了一个有效的程序。
    • “模板”消歧器的全部目的是帮助编译器确定名称是否为模板。但 GCC 决定自行执行此操作,而不使用消歧器,因此在表达式的上下文中找到“GetRef”作为成员。我不认为这种 GCC 行为是正确的。
    • 我没有本地安装 MSVC,但我在我的帖子中链接到了一个似乎使用它的在线编译器,它接受我的测试程序,因此我最初认为 Clang 在错了。
    猜你喜欢
    • 1970-01-01
    • 2011-06-29
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-30
    • 1970-01-01
    相关资源
    最近更新 更多