c++编译器不应用模板
C++ compiler does not apply template
我尝试了模板的第一步。我有一个类,读取配置参数使用boost/property_tree。目前我有几十个getter都做同样的事情。例如:
inline std::string getSocket(void) {
return any_cast<std::string>(param["socket"]);
}
现在我试着创建一个模板:
声明:
template <typename T, typename R>
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]);
}
调用另一个pcp文件:
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 &);
^
我用clang++编译器在Mac OS X 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_
和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
你看,有很多重复的逻辑。我的感觉是,这可以做得更一般。你能给我个提示吗?提前感谢
默认参数在声明中,而不是在定义中:
// 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]);
}
的被害者。调用地点的尖括号是允许的,但这是多余的;以下是更习惯的:
mfsocket = ::config->getValue("socket");
相关文章:
- 如何编译使用从不同编译器编译的库的应用程序?
- 如何使用CLion和MSVC编译器工具链编译wxWidgets Hello World应用程序而没有错误?
- 是否可以将不同的编译器嵌入到我的应用程序中?
- C++使用较新的编译器构建应用程序,而无需重新构建库
- RVO 何时保证应用/确实适用于 C++20 编译器
- 是否可以在 Azure 应用服务中安装 C++ 编译器
- [expr.unary.op]/9 似乎暗示"运算符!()' 不能应用于下面的类型 A.但编译器不同意这一点
- GCC编译器,为较低版本的GCC编译应用程序
- 如何将我的控制台应用程序链接到使用 clang++ 作为编译器的 OSX 环境中的 /usr/local/lib 中存在
- 如何从我的qt应用程序运行gcc编译器?
- 将 const 限定符应用于模板参数时的不同编译器行为
- 尝试使用VC++编译器构建Qt应用程序:"type_traits":没有这样的文件或目录
- 如何安全地部署使用升级的编译器构建的应用程序
- 不同的输出调用clang上的malloc应用编译器选项-00和-03
- 使用英特尔编译器套件编译 OpenMPI 应用
- CL.exe 构建通用应用程序时编译器和库版本不匹配
- 从沙盒应用程序运行clang编译器的任何可能方式
- c++应用程序找不到com dll,因为编译器使用不正确的guid生成.tlh文件
- 要求编译器内联我的类并应用通常的优化
- sizeof可以应用于未捕获的变量的lambda内部吗?还是这是一个编译器错误?