【问题标题】:"Could not deduce template argument" when template argument is specified指定模板参数时“无法推断模板参数”
【发布时间】:2020-07-01 05:15:45
【问题描述】:

我正在尝试用 C++ 编写我自己的简单反射系统。我有以下测试代码:

#include <cstdio>
#include <xtr1common>

// common base class
struct TypeDescriptor { };

// specialization for primitive types
template<class T>
struct Primitive : public TypeDescriptor
{
    static Primitive<T> Instance;
};
Primitive<int> Primitive<int>::Instance;

struct ReflectedType
{
    static TypeDescriptor Reflection;
};

// gets an appropriate TypeDescriptor for a type based on whether it has a Reflection member or not.
// if not, then it expects a Primitive<T> specialization
struct DefaultResolver
{
    // used to calculate IsReflected meta-function
    template<class T> static char func(decltype(&T::Reflection));
    template<class T> static int func(...);
    template<class T>
    struct IsReflected
    {
        enum
        {
            value = (sizeof(func<T>(nullptr)) == sizeof(char))
        };
    };

    // get the TypeDescriptor for a reflected class
    template<class T, typename std::enable_if<IsReflected<T>::value, int>::value = 0>
    static TypeDescriptor* get()
    {
        return &T::Reflection;
    }

    // get the TypeDescriptor for a Primitive<T> if it is not reflected
    template<class T, typename std::enable_if<!IsReflected<T>::value, int>::value = 0>
    static TypeDescriptor* get()
    {
        return &Primitive<T>::Instance;
    }
};

// helper class that provides type-safe access to a type's TypeDescriptor
template<class T>
struct TypeResolver
{
    static TypeDescriptor* get()
    {
        return DefaultResolver::get<T>();
    }
};

int main()
{
    // no problems here, obviously
    TypeDescriptor* desc = &Primitive<int>::Instance;

    // resolves to false, as expected
    constexpr bool isIntReflected = DefaultResolver::IsReflected<int>::value;

    // resolves to true, as expected
    constexpr bool isClassReflected = DefaultResolver::IsReflected<ReflectedType>::value;

    // this does not compile
    desc = TypeResolver<int>::get();

    getchar();
    return 0;
}

我在TypeResolver&lt;int&gt;::get() 遇到问题,出现以下错误:

错误 C2672:“DefaultResolver::get”:找不到匹配的重载函数
注意:在编译类模板成员函数 'TypeDescriptor *TypeResolver::get(void)'
注意:请参阅正在编译的函数模板实例化“TypeDescriptor *TypeResolver::get(void)”的参考
注意:请参阅正在编译的类模板实例化“TypeResolver”的参考
错误 C2783:“TypeDescriptor *DefaultResolver::get(void)”:无法推断“__formal”的模板参数
注意:见'DefaultResolver::get'的声明

我对第二个错误特别困惑。我正在指定模板参数,所以我错过了什么?

【问题讨论】:

    标签: c++ templates reflection metaprogramming template-meta-programming


    【解决方案1】:

    两个问题:

    1. std::enable_if 没有::value 成员类型,只有::type 成员类型,当条件为真时存在。

    2. return DefaultResolver::get&lt;T&gt;() 中,提供显式模板参数会禁用对这些参数的模板参数推导,而std::enable_if is depending on 才能起作用。

    所以首先将std::enable_if 声明中的::value 更改为::type。下一个问题是在提供模板类型的同时允许模板参数推导工作。您可以通过将帮助模板作为函数参数传递来做到这一点,并在 DefaultResolver::get() 的声明中更改您的参数以接受该类类型的对象:

    template <class T>
    struct type_t { };
    // ...
    template <class T,
              typename std::enable_if<IsReflected<T>::value, int>::type = 0>
    static TypeDescriptor* get(type_t<T>);
    
    template <class T,
              typename std::enable_if<!IsReflected<T>::value, int>::type = 0>
    static TypeDescriptor* get(type_t<T>);
    // ...
    template <class T>
    struct TypeResolver
    {
      static TypeDescriptor* get()
      {
        return DefaultResolver::get(type_t<T>{});
      }
    };
    

    希望这会有所帮助。

    【讨论】:

    • 事实证明这确实有帮助,但不需要第 2 部分,只需要第 1 部分。更正以解决问题,谢谢!
    • @MSinger 出于好奇,您使用的是什么编译器?
    猜你喜欢
    • 2013-02-18
    • 1970-01-01
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 2021-11-01
    相关资源
    最近更新 更多