【问题标题】:How do I fix c++ compile with wrapped typedef in a template structure如何在模板结构中使用包装的 typedef 修复 c++ 编译
【发布时间】:2013-01-08 22:03:43
【问题描述】:

此代码将失败并显示错误消息(行号已关闭)。我该如何解决这个问题(保持相同的意图)?

g++ -o c_test c_test.cpp

c_test.cpp:在函数'int main(int, char**)'中:

c_test.cpp:28:18: 错误:没有匹配函数调用'wcalc(CWrapped::u_type&)'

c_test.cpp:28:18: 注意:候选人是:

c_test.cpp:17:58: 注意:模板 int wcalc(typename CWrapped::u_type)

包装的类型被传递给“calc”和“wcalc”函数,但是第二个失败了。 我希望能够包装类型,这样我就可以使用编译时定义来指定不同的类型,但仍然使用相同的包装函数

// Example template class
template <int T_B>
class m_int {
public:
  int x;
  m_int() { x = T_B; }
  int to_int() { return(x); }
};

// Desired Typedef wrap
template <int T_BITS> struct CWrapped {
  typedef m_int<T_BITS> u_type;
};


// This is ok, no wrapping
template <int T_BITS> int calc(m_int<T_BITS> x) {
  return(x.to_int());
}
// This fails when instantiated
template <int T> int wcalc(typename CWrapped<T>::u_type x) {
  return(x.to_int());
}


int main(int argc, char* argv[]) {
  CWrapped<5>::u_type s;

  int x = calc(s);
  int y = wcalc(s);
  return(0);
}

【问题讨论】:

标签: c++ templates typedef


【解决方案1】:

来自 C++11 标准,第 14.8.2.5/16 段

"如果,在一个带有非类型模板参数的函数模板的声明中,该非类型模板参数用在函数参数列表中的子表达式中,则表达式是一个非-推断上下文如上指定。示例:"

template <int i> class A { / ... / };
template <int i> void g(A<i+1>);
template <int i> void f(A<i>, A<i+1>);
void k() {
    A<1> a1;
    A<2> a2;
    g(a1); // error: deduction fails for expression i+1
    g<0>(a1); // OK
    f(a1, a2); // OK
}

"注意:模板参数如果仅在非推导上下文中使用,则不参与模板参数推导。例如:"

template<int i, typename T> 
T deduce(typename A<T>::X x, // T is not deduced hereT t, // but T is deduced here
typename B<i>::Y y); // i is not deduced here
A<int> a;
B<77> b;
int x = deduce<77>(a.xm, 62, b.ym);
// T is deduced to be int, a.xm must be convertible to
// A<int>::X
// i is explicitly specified to be 77, b.ym must be convertible
// to B<77>::Y

由于上述原因,您的非类型模板参数T 无法推断:您必须明确提供:

int main(int argc, char* argv[]) {
  CWrapped<5>::u_type s;

  int x = calc(s);
  int y = wcalc<5>(s); // Template argument 5 cannot be deduced!
  return(0);
}

另请参阅此相关链接:C++, template argument can not be deduced(@NateKohl 提供)

【讨论】:

  • 谢谢,我看不出我的例子是如何比较的。如果编译器能够为 calc 推导出“5”,为什么不能也为“wcalc”推导出来。不确定它是否有资格作为子表达式,因为它只是替换。不幸的是,明确指定“5”会破坏目的,所以我需要考虑另一种方式。再次感谢
  • @user451596:它不适用于wcalc,因为类型推导不会对依赖类型名称执行(即类型名称表示为模板参数的函数,在您的情况下为T)。这就是标准上面引用的第二部分想让你知道的。我想最好在我在答案末尾发布的链接中解释了未完成的原因
  • @user451596:简而言之:对于f(A&lt;T&gt; a)这样的参数,可以推导出a的类型,但是对于f(typename A&lt;T&gt;::type这样的参数,它不能,因为可能有很多Ts 结果是相同的 A&lt;T&gt;::type 并且选择将是模棱两可的(即使编译器可以去寻找所有可能的 Ts)
  • 谢谢安迪,是的,我看到了链接,现在按照您的解释和给定的解释进行操作
  • @user451596:如果您认为我对您的问题给出了令人满意的答案,请考虑将答案标记为已接受。欢呼
【解决方案2】:

您的问题是 CWrapped 是在依赖上下文中从 intu_type 的映射。

您需要一张从u_typeint 的映射才能进行类型推断。

模板类型推导是简单的模式匹配,它不会反转任意模板构造。

例如,您可以通过以下方式提取 CWrapped 将解析为 T 的方法:

template<typename T>
struct GetWrapped;

template<int N>
struct GetWrapped< m_int<N> > {
  typedef CWrapped< N > type;
};

template <int T> int wcalc(T const& x) {
  typedef typename GetWrapped<T>::type CWrappedType; // assuming you need it for something
  return(x.to_int());
}

您只能接受T 在重载决议中有这样的映射:

#include <type_traits>
template <int T> auto wcalc(T const& x)->typename std::enable_if< sizeof(typename GetWrapped<T>::type), int>::type  {
  return(x.to_int());
}

它使用 SFINAE 和 C++11 功能来检查 GetWrapped&lt;T&gt; 是一个有效的构造。

现在,这可能是一个 XY 问题,就像您问过 X 一样,但您确实需要知道 Y。我希望以上其中一项会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 2020-05-22
    • 2023-03-03
    相关资源
    最近更新 更多