Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何允许编译器推断模板化get函数的正确返回类型?_C++_Templates - Fatal编程技术网

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建议的方法替换它(如果