boost :: variant - 为什么模板参数的优先级高于const字符串参数

时间:2012-11-10 07:20:30

标签: c++ templates boost boost-variant

我正在见证以下代码中的一个我不理解的行为。关键是如果我声明operator()的第二个重载,如下所示:

bool operator()(T other) const
bool operator()(const T &other) const

程序的输出是:

  

的字符串

但如果我使用以下声明:

bool operator()(T &other) const

输出将是:

  

其他类型

有人可以解释为什么在后一种情况下没有调用operator()(const string &other)吗?

#include "boost/variant/variant.hpp"
#include "boost/variant/apply_visitor.hpp"

using namespace std;
using namespace boost;

typedef variant<string, int> MyVariant;


class StartsWith
    : public boost::static_visitor<bool>
{
public:
    string mPrefix;
    bool operator()(const string &other) const
    {
        cout << "string" << endl;
        return other.compare(0, mPrefix.length(), mPrefix) == 0;
    }
    template<typename T>
    bool operator()(T &other) const
    {
        cout << "other type" << endl;
        return false;
    }
    StartsWith(string const& prefix):mPrefix(prefix){}
};

int main(int argc, char **argv) 
{
    MyVariant v(string("123456"));
    apply_visitor(StartsWith("123"), v);
    return 0;
}

1 个答案:

答案 0 :(得分:6)

这里有const个问题。

您将const对象传递给apply_visitor - 因此不会将const对象成员传递给应用的访问者。所以在你的情况下它是string& - 对字符串类型的引用。此模板与之完全匹配:

template<typename T>
bool operator()(T &other) const

所以它被选中了。此功能不完全匹配 - 它被跳过:

bool operator()(const string &other) const

当然,如果您提供该运营商:

bool operator()(string &other) const

然后它会被选中,因为非模板函数在模板1之前被考虑。

所以解决方案是:在访问者中提供带有字符串引用(而不是const)的方法 - 或者传递const变量来应用...

第一个解决方案 - 从字符串运算符中删除const:

bool operator()(/*const*/ string &other) const
//              ^^^^^^^^^ remove it

第二个解决方案 - 传递const对象:

const MyVariant& cv = v;
apply_visitor(StartsWith("123"), cv);
//                               ^^ const object passed here

第三种解决方案 - 将const说明符添加到普通访问者:

template<typename T>
bool operator()(const T &other) const
//              ^^^^^ 

第1和第3个解决方案优于第2个 - 您应该将一致的访问者传递给您的变体,当编译器必须选择适当的函数时,const具有强烈的意义。