c++ - 模板实例化解析错误

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

抱歉标题含糊不清,我对问题的理解不够透彻,甚至无法正确描述它。我只是不明白为什么我的 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

最佳答案

此代码基于以下信念:dynamic_cast在标准中被指定为这样的东西:

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

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

所以 &std::dynamic_cast<B, A>没有任何意义。没有 std::dynamic_cast完全dynamic_cast只接受一个类型参数,你不能有一个“部分”动态转换 - 表达式是 dynamic_cast<T>(v) , 你不能只有 dynamic_cast<T>通过它自己。


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

  1. 你不能dynamic_cast一个A*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现在是类型系统的一部分。

关于c++ - 模板实例化解析错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50333108/

相关文章:

c++ - 何时将库包含在 target_link_libraries 中

C++ 与部分模板特化语法混淆

c++ - 一个 MinGW,许多 GCC 版本 - 怎么做?

c++ - 跨平台 unicode 路径处理

c++ - glGetFloatv 导致堆栈粉碎

c++ - 如何定义模板函数重载以匹配空 std::tuple<>?

c - C 中的 long long 乘法给出错误的结果

c++ - 如何消除仅在启用优化时出现的错误

c++ - 如何从 Main 调用 void 函数

c++ - 允许运行时和编译时多态性的灵活方式?