C++ 如何在不指定类名的情况下专门化模板?
我想创建一个名为debug的函数,输出有关对象的一些信息。我的系统包含许多不同类型的对象;其中一些包含其他对象C++ 如何在不指定类名的情况下专门化模板?,c++,templates,template-specialization,one-definition-rule,C++,Templates,Template Specialization,One Definition Rule,我想创建一个名为debug的函数,输出有关对象的一些信息。我的系统包含许多不同类型的对象;其中一些包含其他对象 using namespace std; // for brevity struct dog {string name;}; struct human {string name; string address;}; struct line {list<human*> contents;}; struct pack {vector<dog*> contents;}
using namespace std; // for brevity
struct dog {string name;};
struct human {string name; string address;};
struct line {list<human*> contents;};
struct pack {vector<dog*> contents;};
这里,pack和line的代码几乎相同!我希望避免多次编写相同的代码:
struct line {list<human*> contents; typedef human type;};
struct pack {vector<dog*> contents; typedef dog type;};
template <class T>
void debug(T object) // T here is a compound object (having contents)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<T::type>);
}
但是这种语法与函数模板冲突,因为简单对象具有相同的签名
如何重写代码?我不想重写dog、human等的第一部分声明,因为我程序的这一部分已经非常复杂,向其中添加东西基类、成员函数等只是为了调试似乎不合适。将容器也作为模板参数:
template <template <typename> class Container, typename T>
void debug(Container<T> object)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<T>);
}
当无法使用C++11时。您可以使用SFINAE选择正在使用的重载
我忘记了确切的细节,但您可以使用它来检测内容成员或名称成员的存在,然后基于此进行重载。基本代码可能如下所示:
template <typename T> void debug(T const & x)
{
debug_helper<T, has_name<T>::value>::print(x);
}
我们需要一个助手类:
template <typename, bool> struct debug_helper;
template <typename T> struct debug_helper<T, true>
{
static void print(T const & x) { /* print x.name */ }
};
template <typename T> struct debug_helper<T, false>
{
static void print(T const & x) { /* print x.content */ }
};
现在我们只需要一个SFINAE trait类,它有一个名称和一个打印容器的机制。使用C++11、decltype和SFINAE,这两个问题几乎一字不差地解决了。使事情变得简单:
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
struct dog { std::string name; };
struct human { std::string name; std::string address; };
struct line { std::list<human*> contents; };
struct pack { std::vector<dog*> contents; };
template <typename T>
auto debug(T const& t) -> decltype(t.name, void(0)) {
std::cout << t.name << '\n';
}
template <typename T>
auto debug(T const* t) -> decltype(t->name, void(0)) {
if (t != 0) std::cout << t->name << '\n';
}
struct Debugger {
template <typename T>
void operator()(T const& t) { debug(t); }
};
template <typename C>
auto debug(C const& c) -> decltype(c.contents, void(0)) {
typedef decltype(c.contents) contents_type;
typedef typename contents_type::value_type type;
std::for_each(c.contents.begin(), c.contents.end(), Debugger());
}
int main() {
dog dog1 = { "dog1" }, dog2 = { "dog2" };
human h1 = { "h1" }, h2 = { "h2" };
line l; l.contents.push_back(&h1); l.contents.push_back(&h2);
debug(l);
}
正如所料:
如果没有C++11,它需要一些技巧,但原理仍然是一样的,如果需要创建一个基于名称和内容的存在性和可访问性导致编译错误的结构,则使用boost::enable_
当然,如果您只需将方法连接到结构本身中,这会更容易:实际上,我的简单类也是模板化的。我想根据成员内容的存在而不是参数的模板性来选择调试的版本。参数也编辑了我的问题。@anatolyg:您需要键入def human type,或者使用decltype/typeof。
template <typename T> void debug(T const & x)
{
debug_helper<T, has_name<T>::value>::print(x);
}
template <typename, bool> struct debug_helper;
template <typename T> struct debug_helper<T, true>
{
static void print(T const & x) { /* print x.name */ }
};
template <typename T> struct debug_helper<T, false>
{
static void print(T const & x) { /* print x.content */ }
};
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
struct dog { std::string name; };
struct human { std::string name; std::string address; };
struct line { std::list<human*> contents; };
struct pack { std::vector<dog*> contents; };
template <typename T>
auto debug(T const& t) -> decltype(t.name, void(0)) {
std::cout << t.name << '\n';
}
template <typename T>
auto debug(T const* t) -> decltype(t->name, void(0)) {
if (t != 0) std::cout << t->name << '\n';
}
struct Debugger {
template <typename T>
void operator()(T const& t) { debug(t); }
};
template <typename C>
auto debug(C const& c) -> decltype(c.contents, void(0)) {
typedef decltype(c.contents) contents_type;
typedef typename contents_type::value_type type;
std::for_each(c.contents.begin(), c.contents.end(), Debugger());
}
int main() {
dog dog1 = { "dog1" }, dog2 = { "dog2" };
human h1 = { "h1" }, h2 = { "h2" };
line l; l.contents.push_back(&h1); l.contents.push_back(&h2);
debug(l);
}
h1
h2