【问题标题】:Template instantiation parse error模板实例化解析错误
【发布时间】:2018-05-14 14:43:43
【问题描述】:

抱歉标题含糊不清,我对问题的理解还不够好,甚至无法正确描述。我只是不明白为什么我的main() 的最后一行失败了。适量的嵌套模板调用如下:

#include <iostream>

template <typename T>
struct ObjFirst {};

template <typename T>
struct ObjFirst<void (*)(T)> {
  template <void (*fp)(T)>
  static void f(T arg){fp(arg);}
};

template <typename T, typename R>
struct ObjFirst<R (*)(T)> {
  template <R (*fp)(T)>
  static R f(T arg) {return fp(arg);}
};

template <typename T>
struct Id {
  template <T fn_ptr>
  static auto funcPtr(void) { return &ObjFirst<T>::template f<fn_ptr>; }
};

template <auto fn>
auto id() { return Id<decltype(fn)>::template funcPtr<fn>(); }

int sampleFunc(int) {return 0;}
void sampleFuncV(int) {}

template <typename R, typename T>
R sampleFuncT(T) {return R{};}

template <>
int sampleFuncT<int, int>(int i) {return 7+i;}

struct A {};
struct B : A {};

int main()
{
    id<&sampleFunc>(); // OK
    id<&sampleFuncV>(); // OK
    auto f = id<&sampleFuncT<int, int>>(); // OK
    std::cout << f(3); // Double-checking the result: OK ('10')

    id<&std::dynamic_cast<B, A>>();
    return 0;
}

你可以看到这个模板机制的几个不同的调用工作,但最后一个没有。有一刻我以为这是因为为模板化参数选择了错误的 ObjFirst 特化,但不是。

任何想法表示赞赏。使用 GCC 7、GCC 8 和 clang 6 可以观察到失败:https://godbolt.org/g/5spCJy

【问题讨论】:

    标签: c++ templates gcc clang c++17


    【解决方案1】:

    此代码基于这样的信念,即dynamic_cast 在标准中被指定为如下内容:

    namespace std {
        template <typename Dst, typename Src>
        Dst* dynamic_cast(Src* );
    }
    

    虽然这四种 C++ 类型转换看起来像是函数模板的调用,但它们实际上是核心语言的一部分。这些是关键字,它们没有作用域,虽然它们接受一个看起来像模板类型参数的东西,但实际上不是。

    所以&amp;std::dynamic_cast&lt;B, A&gt; 没有任何意义。根本没有std::dynamic_castdynamic_cast 只接受一个类型参数,而且你不能有一个“部分”动态转换——表达式是dynamic_cast&lt;T&gt;(v),你不能只有dynamic_cast&lt;T&gt; 本身。


    假设std::dynamic_cast 只是std::dynamic_pointer_cast 的拼写错误,那么您的代码还有另外两个问题:

    1. 您不能将dynamic_castA* 转换为B*。您可以向上转换非多态对象/指针,但不能向下转换它们。所以这是不正确的。
    2. 如果您将A 设为多态,那么如果您稍微减少它并使ObjFirst 的基本情况不完整而不是空,问题就会变得更加清晰:

      template <typename T>
      struct ObjFirst;
      
      template <typename T>
      struct ObjFirst<void (*)(T)> {}; 
      
      template <typename T, typename R>
      struct ObjFirst<R (*)(T)> {} ;
      
      struct B { };
      struct D : B { };
      
      int main()
      {
          ObjFirst<decltype(&std::dynamic_pointer_cast<B,D>)> n;
      }
      

    编译失败,报错:

    foo.cxx: In function ‘int main()’:
    foo.cxx:18:57: error: aggregate ‘ObjFirst<std::shared_ptr<B> (*)(const std::shared_ptr<D>&) noexcept> n’ has incomplete type and cannot be defined
         ObjFirst<decltype(&std::dynamic_pointer_cast<B,D>)> n;
                                                             ^
    

    这应该清楚问题是什么。您有 void(*)(T)R(*)(T) 的特化,但 std::dynamic_pointer_cast 也不匹配,因为 noexcept 现在是类型系统的一部分。

    【讨论】:

    • 呃,我真的把dynamic_cast放在那里了吗?这就是我在研究模板错误 8 小时后变成的样子。我的意思是std::dynamic_pointer_cast。让我看看我修复代码后是否真的有任何错误......
    • 是的,修复了问题中的代码,但仍然出现错误(当然是另一个错误)。
    • @VioletGiraffe 你不能把dynamic_castA* 变成B*,你必须走另一条路(或者让A 多态)
    • 也解决了这个问题。
    • 哇。我认为必须在此处实例化基本非专用模板(您演示了一种非常简洁的检查方法,尽管我应该在里面放一个 static_assert),但我不明白为什么会这样。现在我愿意。非常感谢。
    猜你喜欢
    • 2012-01-03
    • 2019-11-17
    • 2014-04-20
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 2018-01-27
    • 1970-01-01
    • 2017-05-12
    相关资源
    最近更新 更多