在没有参数列表的情况下无效使用模板名称“boost::asio::strand”

invalid use of template-name ‘boost::asio::strand’ without an argument list

我有一个旧程序想在 Centos 8 上用 GCC 8.3.1 编译。 make 命令如下所示:

CXXFLAGS = -O2 -std=c++11

all: my_prog

my_prog: my_prog.o
    g++ my_prog.o -o my_prog -lboost_filesystem -lboost_system -lsecond_level_include -lthird_level_include -lboost_regex -lboost_program_options `mysql_config --libs`

这是 make 的输出:

In file included from /usr/local/include/redisclient/redissyncclient.h:16,
                 from /usr/local/include/third_level_include.hpp:11,
                 from /usr/local/include/second_level_include.hpp:40,
                 from my_prog.cpp:9:
/usr/local/include/redisclient/impl/redisclientimpl.h:72:5: error: invalid use of template-name ‘boost::asio::strand’ without an argument list
     boost::asio::strand strand;
     ^~~~~
/usr/local/include/redisclient/impl/redisclientimpl.h:72:5: note: class template argument deduction is only available with -std=c++17 or -std=gnu++17
In file included from /usr/local/include/redisclient/impl/redisclientimpl.h:13,
                 from /usr/local/include/redisclient/redissyncclient.h:16,
                 from /usr/local/include/third_level_include.hpp:11,
                 from /usr/local/include/second_level_include.hpp:40,
from my_prog.cpp:9:
/usr/include/boost/asio/strand.hpp:29:7: note: ‘template<class Executor> class boost::asio::strand’ declared here
 class strand
       ^~~~~~

[剪切大量输出]

所以我按照它的建议做了并将 -std=c++11 替换为 -std=gnu++17 现在 我明白了:

g++ -O2 -std=gnu++17   -c -o my_prog.o my_prog.cpp
In file included from /usr/local/include/redisclient/redissyncclient.h:16,
                 from /usr/local/include/third_level_include.hpp:11,
                 from /usr/local/include/second_level_include.hpp:40,
                 from my_prog.cpp:9:
/usr/local/include/redisclient/impl/redisclientimpl.h:72:5: error: invalid use of template-name ‘boost::asio::strand’ without an argument list
     boost::asio::strand strand;
     ^~~~~
make: *** [<builtin>: my_prog.o] Error 1

考虑到我不打算更改 Redis 的第三方库代码,是否有编译器标志或我可以用来消除此错误的东西?代码曾在Centos 6上用GCC 4.4.7编译过。

编辑:这是错误来源的文件

/*
 * Copyright (C) Alex Nekipelov (alex@nekipelov.net)
 * License: MIT
 */

#ifndef REDISCLIENT_REDISCLIENTIMPL_H
#define REDISCLIENT_REDISCLIENTIMPL_H

#include <boost/array.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/enable_shared_from_this.hpp>

#include <string>
#include <vector>
#include <queue>
#include <map>

#include "../redisparser.h"
#include "../redisbuffer.h"
#include "../config.h"

class RedisClientImpl : public boost::enable_shared_from_this<RedisClientImpl> {
public:
    enum State {
        NotConnected,
        Connected,
        Subscribed,
        Closed
    };  

    REDIS_CLIENT_DECL RedisClientImpl(boost::asio::io_service &ioService);
    REDIS_CLIENT_DECL ~RedisClientImpl();

    REDIS_CLIENT_DECL void handleAsyncConnect(
            const boost::system::error_code &ec,
          const boost::function<void(bool, const std::string &)> &handler);

    REDIS_CLIENT_DECL void close();

    REDIS_CLIENT_DECL State getState() const;

    REDIS_CLIENT_DECL static std::vector<char> makeCommand(const std::vector<RedisBuffer> &items);

    REDIS_CLIENT_DECL RedisValue doSyncCommand(const std::vector<RedisBuffer> &buff);

    REDIS_CLIENT_DECL void doAsyncCommand(
            const std::vector<char> &buff,
            const boost::function<void(const RedisValue &)> &handler);

    REDIS_CLIENT_DECL void sendNextCommand();
    REDIS_CLIENT_DECL void processMessage();
    REDIS_CLIENT_DECL void doProcessMessage(const RedisValue &v);
    REDIS_CLIENT_DECL void asyncWrite(const boost::system::error_code &ec, const size_t);
    REDIS_CLIENT_DECL void asyncRead(const boost::system::error_code &ec, const size_t);

    REDIS_CLIENT_DECL void onRedisError(const RedisValue &);
    REDIS_CLIENT_DECL static void defaulErrorHandler(const std::string &s);

    REDIS_CLIENT_DECL static void append(std::vector<char> &vec, const RedisBuffer &buf);
    REDIS_CLIENT_DECL static void append(std::vector<char> &vec, const std::string &s);
    REDIS_CLIENT_DECL static void append(std::vector<char> &vec, const char *s);
    REDIS_CLIENT_DECL static void append(std::vector<char> &vec, char c);
    template<size_t size>
    static inline void append(std::vector<char> &vec, const char (&s)[size]);

    template<typename Handler>
    inline void post(const Handler &handler);

    boost::asio::strand strand; // Here it is!
    boost::asio::ip::tcp::socket socket;
    RedisParser redisParser;
    boost::array<char, 4096> buf;
    size_t subscribeSeq;
    typedef std::pair<size_t, boost::function<void(const std::vector<char> &buf)> > MsgHandlerType;
    typedef boost::function<void(const std::vector<char> &buf)> SingleShotHandlerType;

    typedef std::multimap<std::string, MsgHandlerType> MsgHandlersMap;
    typedef std::multimap<std::string, SingleShotHandlerType> SingleShotHandlersMap;

    std::queue<boost::function<void(const RedisValue &v)> > handlers;
    MsgHandlersMap msgHandlers;
    SingleShotHandlersMap singleShotMsgHandlers;

    struct QueueItem {
        boost::function<void(const RedisValue &)> handler;
        boost::shared_ptr<std::vector<char> > buff;
    };

    std::queue<QueueItem> queue;

    boost::function<void(const std::string &)> errorHandler;
    State state;
};

template<size_t size>
void RedisClientImpl::append(std::vector<char> &vec, const char (&s)[size])
{
    vec.insert(vec.end(), s, s + size);
}

template<typename Handler>
inline void RedisClientImpl::post(const Handler &handler)
{
    strand.post(handler);
}


#ifdef REDIS_CLIENT_HEADER_ONLY
#include "redisclientimpl.cpp"
#endif

#endif // REDISCLIENT_REDISCLIENTIMPL_H

UPDATE

You're using an old version of that library. Use v0.6.1 or higher: https://github.com/nekipelov/redisclient/pull/53


所有执行器接口已upgraded a (long) while ago

Strands 曾经是嵌套的 typedef(如果启用的话,io_service 中仍然有一个用于“遗留”兼容性的)。

然而,新的继承类型是 boost::asio::strand<Executor>(例如 boost::asio::io_context::executor_type)。您可以轻松地为任何执行者创建一个 strand,例如:

 auto s = make_strand(io_object.get_executor()); 

您看到的是这些名称的明显混淆。我怀疑这可能与

有关
  • 别名为 strand
  • 的本地类型定义
  • 名为 strand 的局部变量(虽然我没有立即看到这将如何导致发布的确切消息)
  • 最有可能:您有一个 using namespace 可以引入新的 strand 模板

有了这些信息,你应该就能搞定了。

当然,如果您发布了代码,我们可以为您展示它。