C++ C++;编译器不应用模板

C++ C++;编译器不应用模板,c++,templates,compiler-errors,c++14,C++,Templates,Compiler Errors,C++14,我试着向模板迈出第一步。我有一个类,它使用boost/property_树读取配置参数。目前,我有几十个getter都做同样的事情。例如: inline std::string getSocket(void) { return any_cast<std::string>(param["socket"]); } inline std::string getSocket(void){ 返回任意_cast(参数[“套接字]); } 现在我尝试创建一个模板: 声明: templa

我试着向模板迈出第一步。我有一个类,它使用boost/property_树读取配置参数。目前,我有几十个getter都做同样的事情。例如:

inline std::string getSocket(void) {
    return any_cast<std::string>(param["socket"]);
}
inline std::string getSocket(void){
返回任意_cast(参数[“套接字]);
}
现在我尝试创建一个模板:

声明:

template <typename T, typename R>
R getValue(const std::string &);
模板
R getValue(const std::string&);
定义:

template <typename T=std::string, typename R=std::string>
R MilterCfg::getValue(const std::string &key) {
    if (param.count(key) == 0)
        return "";
    return any_cast<T>(param[key]);
}
// declaration
template <typename T=std::string, typename R=std::string>
R getValue(const std::string &);

// definition
template <typename T, typename R>
R MilterCfg::getValue(const std::string &key) {
    if (param.count(key) == 0)
        return "";
    return any_cast<T>(param[key]);
}
模板
R MilterCfg::getValue(常量std::字符串和键){
如果(参数计数(键)==0)
返回“”;
返回任何_cast(参数[key]);
}
调用另一个cpp文件:

mfsocket = ::config->getValue<>("socket");
mfsocket=::config->getValue(“socket”);
编译器不接受以下内容:

/Users/croessner/ClionProjects/sigh/src/milter.cpp:491:30: error: no matching member function for call to 'getValue'
    mfsocket = ::config->getValue<>("socket");
               ~~~~~~~~~~^~~~~~~~~~
/Users/croessner/ClionProjects/sigh/src/config.h:112:11: note: candidate template ignored: couldn't infer template argument 'T'
    R getValue(const std::string &);
      ^
/Users/croessner/ClionProjects/sigh/src/milter.cpp:491:30:错误:调用“getValue”时没有匹配的成员函数
mfsocket=::config->getValue(“socket”);
~~~~~~~~~~^~~~~~~~~~
/Users/croessner/ClionProjects/sigh/src/config.h:112:11:注意:已忽略候选模板:无法推断模板参数“t”
R getValue(const std::string&);
^
我用clang++编译器在MacOSX El Capitan上尝试了这一点。我想我真的错过了一些对模板的理解。但我在这里错过了什么

以下是完整的标题:

#ifndef SRC_CONFIG_H_
#define SRC_CONFIG_H_

#include <map>
#include <string>

#include <boost/any.hpp>
#include <boost/program_options/variables_map.hpp>

namespace po = boost::program_options;

extern bool debug;

namespace conf {
    using boost::any_cast;

    typedef std::map<std::string, boost::any> config_t;

    /*!
     * \brief Read a configuration file and store settings
     *
     * All milter settings may be stored in a configuration file. This class
     * reads a default configuration file, if not given as command line
     * argument and extracts all keys and values. For each key that is not
     * found, but requested my the milter, a default value is defined in a
     * local data structure.
     */
    class MilterCfg {
    public:
        MilterCfg(const po::variables_map &);

        virtual ~MilterCfg() = default;

        /*!
         * \brief The milter socket
         *
         * The socket may have one of three formats. First is
         * inet:portnumber\@host, second is inet6:portnumber\@host6 or a unix
         * socket like unix:/pat/to/socket. host and host6 may be a hostname
         * or a valid IP address. IPv6 addresses must be written in squared
         * braces.
         */
        inline std::string getSocket(void) {
            return any_cast<std::string>(param["socket"]);
        }

        /*!
         * The milter will drop its privileges to this user
         */
        inline std::string getUser(void) {
            return any_cast<std::string>(param["user"]);
        }

        /*!
         * The milter will drop its privileges to this group
         */
        inline std::string getGroup(void) {
            return any_cast<std::string>(param["group"]);
        }

        /*!
         * \brief An optional PID file
         *
         * If desired, a PID file may be created on startup. It will be
         * automatically removed, when the milter gets stopped again.
         */
        inline std::string getPidFile(void) {
            return any_cast<std::string>(param["pidfile"]);
        }

        /*!
         * \brief Map file containing S/MIME certificates
         *
         * This file contains a mapping between email addresses and
         * associated S/MIME certificates and keys.
         */
        inline std::string getMapFile(void) {
            return any_cast<std::string>(param["mapfile"]);
        }

        /*!
         * \brief Path to a temporary directory
         *
         */
        inline std::string getTmpDir(void) {
            return any_cast<std::string>(param["tmpdir"]);
        }

#if !__APPLE__ && !defined _NOT_DAEMONIZE
        /*!
         * \brief Bring the milter to background
         *
         * The milter gets a daemon. The root path is set to '/' and the
         * standard in and out channels are closed
         */
        inline bool getDaemon(void) {
            return any_cast<bool>(param["daemon"]);
        }
#endif  // !__APPLE__ && !defined _NOT_DAEMONIZE

        template <typename T, typename R>
        R getValue(const std::string &);

    private:
        /*!
         * \brief Data store for configuration settings
         */
        config_t param;

        /*!
         * \brief Default settings for the milter
         *
         * If a required setting could not be read from the configuration, a
         * default setting will be used from this data structure.
         */
        struct {
            //! \brief Milter socket
            std::string socket  = "inet:4000@127.0.0.1";
            //! \brief Milter system user
            std::string user    = "milter";
            //! \brief Milter system group
            std::string group   = "milter";
            //! \brief Optional PID file
            std::string pidfile = std::string();
#if !__APPLE__ && !defined _NOT_DAEMONIZE
            //! \brief Run the milter as a daemon process
            bool daemon         = false;
#endif  // !__APPLE__ && !defined _NOT_DAEMONIZE
            //! \brief Location for the map file
            std::string mapfile = std::string();
            //! \brief Location for temporary files
            std::string tmpdir = "/tmp";
        } defaults;
    };
}  // namespace conf

#endif  // SRC_CONFIG_H_
\ifndef SRC\u CONFIG\u H_
#定义SRC_CONFIG_H_
#包括
#包括
#包括
#包括
名称空间po=boost::program\u选项;
外部布尔调试;
名称空间配置{
使用boost::any_cast;
类型定义标准::映射配置;
/*!
*\brief读取配置文件并存储设置
*
*所有milter设置都可以存储在配置文件中
*读取默认配置文件(如果不是作为命令行提供)
*参数并提取所有键和值。对于每个不是
*找到了,但请求了milter,在
*本地数据结构。
*/
类MilterCfg{
公众:
MilterCfg(常量po::变量映射&);
virtual~MilterCfg()=默认值;
/*!
*\简要介绍milter插座
*
*套接字可以有三种格式之一
*inet:portnumber\@host,第二个是inet6:portnumber\@host6或unix
*类似于unix的套接字:/pat/to/socket。主机和主机6可以是主机名
*或有效的IP地址。IPv6地址必须以平方写入
*支架。
*/
内联std::字符串getSocket(void){
返回任意_cast(参数[“套接字]);
}
/*!
*milter将删除此用户的权限
*/
内联std::字符串getUser(void){
返回任意_cast(参数[“用户]);
}
/*!
*milter将放弃对该组的特权
*/
内联标准::字符串getGroup(void){
返回任何_cast(参数[“组]);
}
/*!
*\简要说明一个可选的PID文件
*
*如果需要,可以在启动时创建PID文件
*当弥尔顿再次停止时,自动移除。
*/
内联std::字符串getPidFile(void){
返回任何_cast(param[“pidfile”]);
}
/*!
*\包含S/MIME证书的简短映射文件
*
*此文件包含电子邮件地址和电子邮件地址之间的映射
*关联的S/MIME证书和密钥。
*/
内联std::字符串getMapFile(void){
返回任意_cast(param[“mapfile”]);
}
/*!
*\临时目录的简要路径
*
*/
内联std::字符串getTmpDir(void){
返回任何_cast(param[“tmpdir”]);
}
#如果!\uuuuuuuuuuuuuu苹果\uuuuuuuuuu&!已定义\uu未\uuuDaemonize
/*!
*\brief将milter带到后台
*
*milter获得一个守护进程。根路径设置为“/”并且
*标准进出通道关闭
*/
内联bool getDaemon(void){
返回任何_cast(param[“daemon”]);
}
#endif/!\uuuuuuuuuuuuuuuuuuuuuuuu&!已定义\u未\u DAEMONIZE
模板
R getValue(const std::string&);
私人:
/*!
*\配置设置的简要数据存储
*/
配置参数;
/*!
*\简要说明弥尔顿的默认设置
*
*如果无法从配置中读取所需的设置,则
*将从此数据结构使用默认设置。
*/
结构{
//!\brief Milter插座
std::string socket=“inet:4000@127.0.0.1";
//!\brief Milter系统用户
std::string user=“milter”;
//!\brief Milter系统组
std::string group=“milter”;
//!\brief可选PID文件
std::string pidfile=std::string();
#如果!\uuuuuuuuuuuuuu苹果\uuuuuuuuuu&!已定义\uu未\uuuDaemonize
//!\brief将milter作为守护进程运行
bool daemon=false;
#endif/!\uuuuuuuuuuuuuuuuuuuuuuuu&!已定义\u未\u DAEMONIZE
//!\map文件的简要位置
std::string mapfile=std::string();
//!\n临时文件的简要位置
std::string tmpdir=“/tmp”;
}违约;
};
}//名称空间配置
#endif//SRC\u CONFIG\u H_
和cpp文件:

#include "config.h"

#include <iostream>

#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

namespace fs = boost::filesystem;

namespace conf {
    using boost::any_cast;

    MilterCfg::MilterCfg(const po::variables_map &vm) {
        std::string conffile = vm["config"].as<std::string>();

        boost::property_tree::ptree pt;
        try {
            if (fs::exists(fs::path(conffile))
                && fs::is_regular(fs::path(conffile))) {
                boost::property_tree::ini_parser::read_ini(conffile, pt);
            } else {
                std::cerr << "Error: Unable to read config file "
                          << conffile << std::endl;
            }
        }
        catch (const std::exception &e) {
            std::cerr << "Error: " << e.what() << std::endl;
        }

        try {
            param["socket"] = pt.get<std::string>("Milter.socket");
        }
        catch (...) {
            param["socket"] = defaults.socket;
        }

        try {
            param["user"] = pt.get<std::string>("Milter.user");
        }
        catch (...) {
            param["user"] = defaults.user;
        }

        try {
            param["group"] = pt.get<std::string>("Milter.group");
        }
        catch (...) {
            param["group"] = defaults.group;
        }

        try {
            param["pidfile"] = pt.get<std::string>("Milter.pidfile");
        }
        catch (...) {
            param["pidfile"] = defaults.pidfile;
        }

        try {
            param["mapfile"] = pt.get<std::string>("Milter.mapfile");
        }
        catch (...) {
            param["mapfile"] = defaults.mapfile;
        }

        try {
            param["tmpdir"] = pt.get<std::string>("Milter.tmpdir");
        }
        catch (...) {
            param["tmpdir"] = defaults.tmpdir;
        }

#if !__APPLE__ && !defined _NOT_DAEMONIZE
        try {
            param["daemon"] = pt.get<bool>("Milter.daemon");
        }
        catch (...) {
            param["daemon"] = defaults.daemon;
        }
#endif  // !__APPLE__ && !defined _NOT_DAEMONIZE

        if (::debug) {
            std::cout << "Configuration file values:" << std::endl;

            std::cout << "user="
                << any_cast<std::string>(param["user"])
                << std::endl;
            std::cout << "group="
                << any_cast<std::string>(param["group"])
                << std::endl;
            std::cout << "socket="
                << any_cast<std::string>(param["socket"])
                << std::endl;
            std::cout << "pidfile="
                << any_cast<std::string>(param["pidfile"])
                << std::endl;
#if !__APPLE__ && !defined _NOT_DAEMONIZE
            std::cout << "daemon="
                << std::boolalpha << any_cast<bool>(param["daemon"])
                << std::endl;
#endif  // !__APPLE__ && !defined _NOT_DAEMONIZE
            std::cout << "mapfile="
                << any_cast<std::string>(param["mapfile"])
                << std::endl;
            std::cout << "tmpdir="
                << any_cast<std::string>(param["tmpdir"])
                << std::endl;
        }
    }

    template <typename T=std::string, typename R=std::string>
    R MilterCfg::getValue(const std::string &key) {
        if (param.count(key) == 0)
            return "";
        return any_cast<T>(param[key]);
    }

}  // namespace conf
#包括“config.h”
#包括
#包括
#包括
#包括
名称空间fs=boost::filesystem;
名称空间配置{
使用boost::any_cast;
MilterCfg::MilterCfg(常量po::变量映射和vm){
std::string conffile=vm[“config”].as();
boost::property_tree::ptree pt;
试一试{
if(fs::exists(fs::path(conffile))
&&fs::是_正则的(fs::path(conffile))){
boost::property_tree::ini_parser::read_ini(conffile,pt);
}否则{

默认参数出现在声明中,而不是定义中
mfsocket = ::config->getValue("socket");