无法推断模板参数

couldn't deduce template parameter

本文关键字:参数      更新时间:2023-10-16

我正在尝试使用类似于以下的API:

#include<iostream>
#include<boost/optional.hpp>
class Base
{
 int id;
public:
 int get_id()
 {
    return id;
 }
};
class A : public Base
{
};
class B : public Base
{
};
class M
{
public:
    enum Type
    {
     t_A,
     t_B
    };
    Type type;
    boost::optional<A&> a;
    boost::optional<B&> b;
    boost::optional<A&> get_A()
    {
        return a;
    }
    boost::optional<B&> get_B()
    {
        return b;
    }
};

我需要通过任何派生类到达基类。所以我创建了一个像这样的模板化函数:

template<class T>
boost::optional<T&> get(M & m)
{
    switch(m.type)
    {
    case M::t_A :
        return m.get_A();
    case M::t_B :
        return m.get_B();
    default:
        throw;
    };
}
int main()
{
    M m;
    //... initialization of m
    int i = get<>(m)->get_id();
    return 0;
}

但是我的函数的模板参数不能被推导出来:

template_sp_1.cpp:63:17: error: no matching function for call to ‘get(M&)’
  int i = get<>(m)->get_id();
                 ^
template_sp_1.cpp:63:17: note: candidate is:
template_sp_1.cpp:46:21: note: template<class T> boost::optional<T&> get(M&)
 boost::optional<T&> get(M & m)
                     ^
template_sp_1.cpp:46:21: note:   template argument deduction/substitution failed:
template_sp_1.cpp:63:17: note:   couldn't deduce template parameter ‘T’
  int i = get<>(m)->get_id();

尝试以下任何操作都是不可能的;显然是因为使用了boost::optional:

int i = get<Base>(m)->get_id();
int i = get<A>(m)->get_id();
int i = get<B>(m)->get_id();
对于这种情况,你有什么解决方案吗?(我不能触摸API)

编译器错误非常明显:由于T不依赖于任何函数参数,并且您没有显式传递该T,因此编译器无法推断T的值

请注意,这些a和b可选具有不同的类型,因此您的get()函数试图返回多个不同的类型(因此您使用模板化的可选?)

c++不以这种方式工作,因为类型应该在编译时确定,而您的决定取决于运行时值(开关的事情)。考虑返回一个像boost::variant这样的变体类型

正如@Manu343726已经指出的,您的get()函数具有不同的返回类型。但是既然AB有共同的基类Base,为什么不使用返回类型Base&呢?

boost::optional中有一个关于引用的bug,在boost 1.58中修复了,所以你至少需要这个版本。我修改了你的例子来展示它是如何工作的:

#include <boost/optional.hpp>
#include <boost/version.hpp> 
#include <iostream>

#if BOOST_VERSION < 105800
#error boost version must be at least 1.58
#endif
class Base
{
 int id;
public:
 Base(int id) : id(id) {}
 int get_id()
 {
    return id;
 }
};
class A : public Base
{
public:
    A() : Base(100) {}
};
class B : public Base
{
public:
    B() : Base(999) {}
};
class M
{
public:
    enum Type
    {
     t_A,
     t_B
    };
    Type type;
    boost::optional<A&> a;
    boost::optional<B&> b;
    boost::optional<A&> get_A()
    {
        return a;
    }
    boost::optional<B&> get_B()
    {
        return b;
    }
};

Base& get(M & m)
{
    switch(m.type)
    {
    case M::t_A :
        return (*(m.get_A()));
    case M::t_B :
        return (*(m.get_B()));
    default:
        throw;
    };
}
int main()
{
    A a;
    M m;
    m.type = M::t_A;
    m.a = a;
    Base& base = get(m);
    std::cout << base.get_id() << std::endl;
    return 0;
}

这个例子将输出:

100

这当然只在运行时有效,如果API保证get_A()get_B()返回一个包含有效引用的可选值。如果不能保证这一点,您可以使用如下内容:

boost::optional<Base&> get(M & m)
{
    boost::optional<Base&> base;
    switch(m.type)
    {
    case M::t_A:
        base = m.get_A();
        break;
    case M::t_B :
        base = m.get_B();
        break;
    default:
        throw;
    };
    return base;
}