C++ 写一篇多维的文章;“数学函数”;使用C++;11可变模板
我想编写一个模拟数学函数行为的C++11类。该类将定义函数的集合作为输入,并且可以设置并获取与域中特定点关联的值 由于组成函数域的集合数量是未知的,我想使用C++11可变模板来定义类,如下所示:C++ 写一篇多维的文章;“数学函数”;使用C++;11可变模板,c++,c++11,variadic-templates,variadic-functions,C++,C++11,Variadic Templates,Variadic Functions,我想编写一个模拟数学函数行为的C++11类。该类将定义函数的集合作为输入,并且可以设置并获取与域中特定点关联的值 由于组成函数域的集合数量是未知的,我想使用C++11可变模板来定义类,如下所示: template<typename first_set_type, typename... additional_sets_type> class Function; Function<int, std::string, double> three_dim_function(S
template<typename first_set_type, typename... additional_sets_type> class Function;
Function<int, std::string, double> three_dim_function(S1, S2, S3);
最有可能的是,std::unordered_map
是存储域和编码域之间绑定的理想数据成员:
std::unordered_map<std::tuple<first_set_type, additional_set_types...>, double> data_;
std::无序的地图数据;
尽管这两个问题并不完全相同,我还是尝试从中改编代码(在我的情况下,我可能不需要存储每个std::set
)
编辑#1:我会尽量强调我面临的问题。在链接问题中,类是通过递归调用创建的。然而,在我的例子中,我很难理解如何实现构造函数,即如何从输入集开始设置函数的域。一种可能的方法是使用构造函数预填充由数据
数据成员的输入集的笛卡尔积生成的所有键。问题是我不知道如何迭代参数包
暂定解决方案#1
下面是一个初步的实现:基于@robert mason的贡献。不幸的是,只要调用
位于\u域()
,它就不会编译(clang 4.1,OSX 10.8.4)。然而,乍一看,一切似乎都很好。有什么问题吗?我在下面留下我的原始答案,但我会尝试用可变模板来回答您的问题
对于可变函数模板,您不需要迭代参数包。您必须改为使用递归函数
然后我会使用类似于:
template <class FirstDomain, class ...Domains>
class Function {
public:
typedef std::tuple<FirstDomain, Domains...> domain_t;
static constexpr size_t dimension = sizeof...(Domains) + 1; //+1 for FirstDomain
private:
std::tuple<std::set<FirstDomain>, std::set<Domains>...> domain;
std::unordered_map<domain_t, double> map;
template <size_t index = 0>
typename std::enable_if<(index < dimension), bool>::type
is_in_domain(const domain_t& t) const {
const auto& set = std::get<index>(domain);
if (set.find(std::get<index>(t)) != set.end()) {
return is_in_domain<index + 1>(t);
}
return false;
}
template <size_t index = 0>
typename std::enable_if<!(index < dimension), bool>::type
is_in_domain(const domain_t& t) const {
return true;
}
public:
Function(std::set<FirstDomain> f, std::set<Domains>... ds) :
: domain(f, ds...) {}
};
three_dim_function.set(1, "a", 1.23, 12);
double twelve = three_dim_function.get(1, "a", 1.23);
如果你想让它看起来更好,你可以做一些语法糖:
template <class first_type, class ...addl_types>
class Function {
public:
//...
//left as an exercise for the reader
void set(std::tuple<first_type, addl_types...>, double);
class set_proxy {
friend class Function<first_type, addl_types...>;
std::tuple<first_type, addl_types...> input;
Function<first_type, addl_types...>& parent;
set_proxy(std::tuple<first_type, addl_types...> t, Function<first_type, addl_types...>& f)
: input(t), parent(f) {}
set_proxy(const set_proxy&) = delete;
set_proxy& operator=(const set_proxy&) = delete;
public:
//yes, I know this isn't the right return type, but I'm not sure what's idiomatic
void operator=(double d) {
parent.set(input, d);
}
};
set_proxy set(first_type f, addl_types... addl) {
return set_proxy{std::make_tuple(f, addl...), *this};
}
};
模板
类函数{
公众:
//...
//留给读者作为练习
空集(std::tuple,double);
类集合\代理{
友元类函数;
std::元组输入;
功能&父级;
set_代理(std::tuple t,Function&f)
:输入(t),父(f){}
set_proxy(const set_proxy&)=delete;
set_proxy&operator=(const set_proxy&)=delete;
公众:
//是的,我知道这不是正确的返回类型,但我不确定什么是惯用的
void运算符=(双d){
父集合(输入,d);
}
};
集合\代理集合(第一个\类型f,添加\类型…添加){
返回集_proxy{std::make_tuple(f,addl…,*this};
}
};
这样您就可以执行以下操作:
Function<int, std::string, double> three_dim_function;
three_dim_function.set(1, "a", 1.23) = 12;
功能三维功能;
三维函数集(1,“a”,1.23)=12;
问题是什么?你试过什么?我试着完全按照问题中的描述实现这个类。事实上,我没有提供代码,但我担心它不会有多大帮助。这就是为什么我更愿意描述我的问题。那么对于一个N维的函数
,您设置的N元组是映射到值的set()
还是映射到值的get()
?在我看来,你只需要为一个值设置一个键。也就是说,你有一个元组映射还是一个元组映射?我有一个元组映射。因此,对于函数域中的每个点,即元组
(映射键),对应于编码域中的一个且仅一个点,即与元组关联的双
值。感谢您的回答。如何处理未知数量的输入集?我不想按数学函数的每个维度创建一个类(例如,2DFunction,3dffunction)。我不理解你的问题。如果您看一下将处理所有这些问题的简短代码示例。您可以使用封闭类的可变参数包作为函数的参数类型。我更新了问题,希望问题现在更清楚。谢谢。输入集是有限的。函数
类将形式为
(表示输入集数量的n
)的每个元组与双标量相关联。由于函数仅为作为输入集笛卡尔积获得的点定义,因此必须提前知道提供给setter/getter的特定点是否确实是有效点。检查这一点的一种可能方法是在构造函数中为数据创建所有可能的键。在setter和getter中,您可以使用数据\uu.at(point)
来验证该点是否属于函数域。好的,谢谢,这更清楚了。给我一点时间,我来敲定一些事情。
Function<int, std::string, double> three_dim_function;
three_dim_function.set(1, "a", 1.23) = 12;