模板未解析类型以更正重载
Template isn't resolving type to correct overload
这是在Visual Studio 2010上,使用Boost v1.48.0。我正试图获得一个boost::变体,其中包含一些structs和指向structs的共享指针,以匹配boost::static_cvisitor的正确成员,但没有成功。。。
对于我的问题,让我们建立这个前提,作为一个例子:
struct t_type_A { int key; foo value; };
struct t_type_B { int key; bar value; };
struct t_type_C { int key; baz value; };
struct t_type_D { int key; qux value; };
bool operator<(const t_type_A &, const t_type_A &);
bool operator<(const t_type_B &, const t_type_B &);
bool operator<(const t_type_C &, const t_type_C &);
bool operator<(const t_type_D &, const t_type_D &);
bool operator==(const t_type_A &, const t_type_A &);
bool operator==(const t_type_B &, const t_type_B &);
bool operator==(const t_type_C &, const t_type_C &);
bool operator==(const t_type_D &, const t_type_D &);
typedef std::shared_ptr<t_type_C> t_shared_C;
typedef std::shared_ptr<t_type_D> t_shared_D;
typedef boost::variant<t_type_A, t_type_B, t_shared_C, t_shared_D> t_variant;
我有一位访客如下:
class variant_less : public boost::static_visitor<bool>
{
public:
template<typename T>
result_type operator()(const T &left, const T &right) const
{
return left.value < right.value || (left.value == right.value && left.key < right.key);
}
template<typename T, typename U>
result_type operator()(const T &left, const U &right) const
{
return left.key < right.key;
}
template<typename T>
result_type operator()(const std::shared_ptr<T> &left, const std::shared_ptr<T> &right) const
{
return left->value < right->value || (left->value == right->value && left->key < right->key);
}
template<typename T, typename U>
result_type operator()(const std::shared_ptr<T> &left, const std::shared_ptr<U> &right) const
{
return left->key < right->key;
}
};
在实践中,当我将访问者应用于我的变体时,我会得到一个编译器错误:
编辑:我不得不再次查看错误消息。我把它误译成这个例子,它不是在抱怨"价值",而是在抱怨"关键"。错误已在下面修复。
错误C2039:"key":不是"std::tr1::shared_ptr<"的成员_Ty>'
编译器将两个t_shared_C或两个t_shared_D之间的比较解析为:
template<typename T, typename U>
result_type operator()(const T &left, const U &right) const
是最合适的。这显然不是我想要的。或者,基于我对SFINAE的不可靠了解,我尝试了以下方法:
class variant_less : public boost::static_visitor<bool>
{
public:
template<typename T>
result_type operator()(const T &left, const T &right) const
{
return left.value < right.value || (left.value == right.value && left.key < right.key);
}
template<typename T, typename U>
result_type operator()(const T &left, const U &right) const
{
return left.key < right.key;
}
template<typename T>
result_type operator()(const T &left, const T &right) const
{
return left->value < right->value || (left->value == right->value && left->key < right->key);
}
template<typename T, typename U>
result_type operator()(const T &left, const U &right) const
{
return left->key < right->key;
}
};
我做错了什么?我不想放弃并为每个组合编写重载。
编辑:以下是它的调用方式:
typedef boost::multi_index::multi_index_container<
t_variant_vector,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<variant_extractor<1234>, variant_less>
, boost::multi_index::ordered_non_unique<variant_extractor<5678>, variant_less>
// arbitrarily more indexes go here
>
> t_variant_multi_index;
向量是变量的排序向量,按关键字排序。索引是根据具有特定"key"值的变体的存在来进行索引的。variantextractor查找并提取具有匹配密钥的变体。作为mult_index随后所做工作的简要说明,"关键字提取器"(一种变体)的结果随后被用作"比较谓词"variant_less的参数,用于对该索引进行排序。
问题是apply_visitor
必须为变量内容的所有组合实例化MultiVisitor的operator()
:调用哪个函数是运行时的决定(因为变量内容的类型只有在运行时才知道)。
因此,MultiVisitor必须支持所有参数的组合。这包括其中一个参数是shared_ptr
但另一个不是的组合。
这里有一个解决方案,只需打开所有shared_ptr
的包装。这也消除了代码重复。
class variant_less : public boost::static_visitor<bool>
{
private:
template<typename T>
result_type impl(const T &left, const T &right) const
{
return left.value < right.value
|| (left.value == right.value && left.key < right.key);
}
template<typename T, typename U>
result_type impl(const T &left, const U &right) const
{
return left.key < right.key;
}
template<typename T>
static T const& unpack(T const& p)
{
return p;
}
template<typename T>
static T const& unpack(std::shared_ptr<T> const& p)
{
return *p;
}
public:
template<typename T, typename U>
result_type operator()(const T& left, const U& right) const
{
return impl(unpack(left), unpack(right));
}
};
实例
这与模板实例化有关。编译时,T和shared_ptr都被视为某个类型,编译器不会区分普通类型或share_ptr类型,因此编译器会找到第一个匹配的模板函数定义来实例化函数,这就是错误发生的原因。
你可以做一些类似于std特征的事情:提供两种标签类型:
struct plain_type_tag{};
struct shareptr_type_tag{};
然后将您的功能更改为:
template<typename T, typename U>
result_type operator()(const T &left, const U &right, plain_type_tag) const
{
return left.key < right.key;
}
template<typename T>
result_type operator()(const std::shared_ptr<T> &left, const std::shared_ptr<T> &right, shareptr_type_tag) const
{
return left->value < right->value || (left->value == right->value && left->key < right->key);
}
供您参考:
- "迭代特性"导论。它处理类似的问题
- 函数模板:解释函数模板实例化
- 从父命名空间重载类型
- 如何确保接受的C++模板类型使运算符重载?
- 模板化类如何解析在其类型之一上调用的重载非成员函数?
- 错误:表达式必须具有算术、无作用域枚举或带有运算符重载的指针类型
- 泛型枚举和其他类型的重载模板函数
- 避免在人为的重载函数调用中拼写出类型
- 为什么重载运算符可以返回其返回类型以外的其他内容?
- 为什么在传递长整型时调用具有两个双精度类型的参数的重载函数?
- 重载模板函数未为特定类型选择正确的版本
- 如何为流输出运算符提供重载<<模板'using'类型别名?
- MSVC 错误:4 个重载中的任何一个都无法转换所有参数类型
- 具有重载类型转换运算符的函数对象崩溃
- 为什么在指定重载类型的返回值时出现编译错误
- 忽略C++重载类型转换运算符
- 重载 C++ 类型以处理自定义类
- 重载类型强制转换运算符,以强制转换为指向函数的指针
- C++中的一元运算符重载类型(新手)
- 函数不能在模板实例中推导出重载类型
- 重载类型转换运算符的语法
- 重载 C++ 类型转换(函数)