C++ 如何允许编译器推断模板化get函数的正确返回类型?
我有一堆结构,都有一些元素:C++ 如何允许编译器推断模板化get函数的正确返回类型?,c++,templates,C++,Templates,我有一堆结构,都有一些元素: struct myExample { std::string elem0; int elem1; }; 如果我能做到以下几点,我就可以避免大量的编码。 编写一个模板化get方法,该方法将索引作为模板参数,并从上面的结构返回elem template<int idx, typename K, typename T> T get(const K&) { throw std::runtime_error("should n
struct myExample
{
std::string elem0;
int elem1;
};
如果我能做到以下几点,我就可以避免大量的编码。
编写一个模板化get方法,该方法将索引作为模板参数,并从上面的结构返回elem
template<int idx, typename K, typename T> T get(const K&)
{
throw std::runtime_error("should not happen");
}
template<> std::string get<0, myExample, std::string>(const myExample& k)
{
return k.elem0;
}
template<> int get<1, myExample, int>(const myExample& k)
{
return k.elem1;
}
template T get(常数K&)
{
抛出std::runtime_错误(“不应该发生”);
}
模板std::字符串get(constmyexample&k)
{
返回k.elem0;
}
模板int get(const myExample&k)
{
返回k.elem1;
}
以下是示例的主要功能:
int main()
{
myExample test;
test.elem0 = "hello world";
test.elem1 = 42;
// does not work:
//std::string get0 = ::get<0>(test);
//int get1 = ::get<1>(test);
// does not work either:
//std::string get0 = ::get<0, myExample>(test);
//int get1 = ::get<1, myExample>(test);
// works:
std::string get0 = ::get<0, myExample, std::string>(test);
int get1 = ::get<1, myExample, int>(test);
std::cout<<get0<<":"<<get1<<std::endl;
return 0;
}
intmain()
{
myExample试验;
test.elem0=“你好世界”;
test.elem1=42;
//不起作用:
//std::string get0=::get(test);
//int get1=::get(测试);
//也不起作用:
//std::string get0=::get(test);
//int get1=::get(测试);
//作品:
std::string get0=::get(test);
int get1=::get(测试);
std::cout编译器在考虑专门化之前必须推导所有模板参数,并且它无法以这种方式推导T
只需完全删除typename T
参数,就不需要了
您可能还想考虑一个更容易的替代方案:
template <int Index, typename T> auto get(const T &object)
{
return std::get<Index>(std::tie(object.elem0, object.elem1, object.elem2));
}
模板自动获取(const T&object)
{
返回std::get(std::tie(object.elem0,object.elem1,object.elem2));
}
编译器必须在考虑专门化之前推导出所有模板参数,并且它无法以这种方式推导出T
只需完全删除typename T
参数,就不需要了
您可能还想考虑一个更容易的替代方案:
template <int Index, typename T> auto get(const T &object)
{
return std::get<Index>(std::tie(object.elem0, object.elem1, object.elem2));
}
模板自动获取(const T&object)
{
返回std::get(std::tie(object.elem0,object.elem1,object.elem2));
}
我认为您有一点输入错误,可能会让试图解决模板问题的编译器感到困惑。在这两行中:
template<> int get<2, myExample, int>(const myExample& k) { return k.elem1_; }
template<> boost::gregorian::date get<2, myExample, boost::gregorian::date>(const myExample& k) { return k.elem2_; }
template int get(const myExample&k){return k.elem1}
模板boost::gregorian::date get(const myExample&k){return k.elem2}
两个模板都有相同的索引,2。我想你的意思是1表示int专门化
因此,我猜在索引2的某些场景中,编译器无法决定int和日期。我认为您有一点输入错误,这可能会让编译器在尝试解决模板问题时感到困惑。在这两行中:
template<> int get<2, myExample, int>(const myExample& k) { return k.elem1_; }
template<> boost::gregorian::date get<2, myExample, boost::gregorian::date>(const myExample& k) { return k.elem2_; }
template int get(const myExample&k){return k.elem1}
模板boost::gregorian::date get(const myExample&k){return k.elem2}
两个模板都有相同的索引,2。我想你的意思是1表示int专门化
所以我猜在索引2的某些场景中,编译器无法决定int和date之间的关系。不要使用模板函数专门化,这几乎总是一个坏主意
而是使用重载和转发
template<int idx>
using index_t = std::integral_constant<int, idx>;
// compile time error if it doesn't match
template<int i, class K>
void special_get(index_t<i>, const K&) = delete;
template<int idx, typename K>
decltype(special_get( index_t<idx>{}, std::declval<K const&>() ) )
get(const K& k) {
return special_get( index_t<idx>{}, k );
}
模板
使用指数t=std::积分常数;
//如果不匹配,则出现编译时错误
模板
void special_get(index_t,const K&)=delete;
模板
decltype(特殊的获取(索引{},std::declval())
get(const K&K){
返回特殊的(索引{},k);
}
没有专门知识
inline std::string special_get(index_t<0>, const myExample& k) {
return k.elem0;
}
inline int special_get(index_t<1>, const myExample& k) {
return k.elem1;
}
inline std::字符串特殊获取(索引、常量myExample&k){
返回k.elem0;
}
内联int特殊获取(索引、常量myExample&k){
返回k.elem1;
}
这些是special\u get
的重载。选择哪一个是通过重载解析而不是模板专门化来选择的
模板函数的专门化不应该是解决任何问题的第一、第二或第三选择。不要使用模板函数专门化,这几乎总是一个坏主意
而是使用重载和转发
template<int idx>
using index_t = std::integral_constant<int, idx>;
// compile time error if it doesn't match
template<int i, class K>
void special_get(index_t<i>, const K&) = delete;
template<int idx, typename K>
decltype(special_get( index_t<idx>{}, std::declval<K const&>() ) )
get(const K& k) {
return special_get( index_t<idx>{}, k );
}
模板
使用指数t=std::积分常数;
//如果不匹配,则出现编译时错误
模板
void special_get(index_t,const K&)=delete;
模板
decltype(特殊的获取(索引{},std::declval())
get(const K&K){
返回特殊的(索引{},k);
}
没有专门知识
inline std::string special_get(index_t<0>, const myExample& k) {
return k.elem0;
}
inline int special_get(index_t<1>, const myExample& k) {
return k.elem1;
}
inline std::字符串特殊获取(索引、常量myExample&k){
返回k.elem0;
}
内联int特殊获取(索引、常量myExample&k){
返回k.elem1;
}
这些是special\u get
的重载。选择哪一个是通过重载解析而不是模板专门化来选择的
专门化模板函数不应该是您解决任何问题的第一个、第二个或第三个选择。听起来您好像在试图重新创建所提供的功能。@RSahu虽然std::tuple
缺少字段名。@HolyBlackCat,我会让OP澄清,但不清楚字段名对您是否重要他们。请演示一个不起作用的方法并演示您的问题。人们正在猜测您的意思(可能准确,可能不准确)因为您的问题不包含。@Yakk我添加了一个示例。听起来您好像在试图重新创建由提供的功能。@RSahu虽然std::tuple
缺少字段名。@HolyBlackCat,我会让OP澄清,但不清楚字段名对他们是否重要。请演示一个不起作用的示例人们正在猜测你的意思(也许准确,也许不准确)因为你的问题不包含一个。@Yakk我添加了一个例子。出于某种奇怪的原因,我不应该在部门的任何代码中使用auto…@初学者:那么一些模板元编程技术在C++中是不可能的,如果我删除T,我必须写一个返回类型,但没有一个返回类型。我如何删除从get函数中选择T参数并避免使用auto?@AndyG在没有auto的情况下,是否有办法做到这一点?@初学者IMHO这个例子证明了一个例外。auto
可以在许多方面被误用,但这不是其中之一。如果必须,请用下面Sirgay建议的方法替换它(如果