当前位置: 首页 > 知识库问答 >
问题:

在类模板的变量函数模板上定义成员变量

呼延震博
2023-03-14

我试图在变量函数模板上使用'decltype'来获取其返回值类型,然后使用它来定义成员变量。但我一直在犯这样的错误:

D:\Qt Projects\OpenGL_PhysicsSim\lib\Physics Effects\include\ParticleList.hpp:89: error: cannot convert 'std::tuple<std::uniform_real_distribution<double>, std::uniform_real_distribution<double>, std::uniform_real_distribution<double> >' to 'int' in assignment
     distributionTuple = createDistribution<Type, Types...>(meanValue, meanValues..., varianceValue, varianceValues...);

基本上,decltype失败并将distributionTuple声明为int,而不是推断createDistribution的返回类型。

template<typename AttributeType, typename Type, typename ...Types>
class ParticleAttributeGenerator
{
private:
 template<typename T>
 auto createDistribution(T meanValue, T varianceValue)
 {
   static_assert(
     std::is_integral<Type>::value || std::is_floating_point<Type>::value,
     "Type should be either integral value or floating point value");

   using distType = typename std::conditional< std::is_integral<T>::value,
                                               std::uniform_int_distribution<>,
                                               std::uniform_real_distribution<> >::type;
   T a = meanValue - varianceValue;
   T b = meanValue + varianceValue;

   return std::tuple<distType>(distType(a,b));
 }

 template<typename Tfirst, typename ...Trest>
 auto createDistribution(Tfirst meanValue, Trest... meanValues, Tfirst varianceValue, Trest... varianceValues)
 {
   static_assert(
     std::is_integral<Type>::value || std::is_floating_point<Type>::value,
     "Type should be either integral value or floating point value");

   using distType = typename std::conditional< std::is_integral<Tfirst>::value,
                                               std::uniform_int_distribution<>,
                                               std::uniform_real_distribution<> >::type;
   Tfirst a = meanValue - varianceValue;
   Tfirst b = meanValue + varianceValue;

   static_assert((sizeof...(meanValues)) == (sizeof...(varianceValues)), "number of meanValues and varianceValues should match!");

   return std::tuple_cat(std::tuple<distType>(distType(a,b)), createDistribution<Trest...>(meanValues..., varianceValues...));
 }

public:
 ParticleAttributeGenerator(Type meanValue, Types... meanValues, Type varianceValue, Types... varianceValues)
 {
   distributionTuple = createDistribution<Type, Types...>(meanValue, meanValues..., varianceValue, varianceValues...);  // 89 : error          
 }

private:
  //using result_type_t = typename std::result_of<createDistribution(Type, Types..., Type, Types...)>::type;
  decltype (createDistribution<Type, Types...>(Type, Types..., Type, Types...)) distributionTuple;
  //decltype (createDistribution<Type, Types...>(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)) distributionTuple;
};

它的工作原理是当我提供create分发的所有参数的值,但这不是我要找的行为。因为我不知道该函数有多少参数,所以它必须保持为可变模板函数。

我计划如何使用类模板的示例:

ParticleAttributeGenerator<glm::vec3, float, float, float> example1(3.0f, 1.0f, 3.0f, 1.0f, 3.0f, 1.0f);
ParticleAttributeGenerator<glm::u8vec4, uint8_t, uint8_t, uint8_t, uint8_t> example2(3, 2, 25, 5, 51, 12, 32, 3);

如果我没有任何成员变量,并使用分布式元组作为:

auto distributionTuple = createDistribution<Type, Types...>(meanValue, meanValues..., varianceValue, varianceValues...);

它编译,因此我相信create分发能够递归地定义元组。但那对我没用。我一定是错过了什么不对劲的地方。我在-std=c 14模式下使用GCC 4.9.2。

共有2个答案

卢志行
2023-03-14

当需要在未计算的上下文中构造函数的完整调用时,请使用std::declval。使用它,您将声明distributionTuple,如下所示:

decltype (std::declval<ParticleAttributeGenerator>().createDistribution<Type, Types...>(std::declval<Type>(), std::declval<Types>()..., std::declval<Type>(), std::declval<Types>()...)) distributionTuple;
赫连泰宁
2023-03-14

首先,让我们将示例简化为一些更易于管理、外部内容更少的内容:

template <typename T>
class Bar
{
private:
    template <typename U>
    auto foo(U a, U b)
    {
        return std::tuple<U>(a+b);
    }

public:
    Bar(T a, T b)
    {
        distributionTuple = foo<T>(a, b);
    }

private:
    decltype (foo<T>(T, T)) distributionTuple;
};

int main()
{
    Bar<int> b(4, 4);
}

这给出了问题中出现的示例编译错误(无法转换std::tuple)

foo<T>(T, T)

不是有效的函数调用。您需要调用foo

foo<T>(std::declval<T>(), std::declval<T>())

一旦进行了更改,您将得到一个新的编译错误:“不能在没有对象的情况下调用成员函数foo。”因此,让我们再次添加一个带有declval的对象。汇编如下:

template <typename T>
class Bar
{
private:
    template <typename U>
    auto foo(U a, U b)
    {
        return std::tuple<U>(a+b);
    }

public:
    Bar(T a, T b)
    {
        distributionTuple = foo<T>(a, b);
    }

private:
    decltype(std::declval<Bar>().foo<T>(
                 std::declval<T>(), 
                 std::declval<T>())
             ) distributionTuple;
};

 类似资料:
  • 我试图用成员模板函数实现一个可变类模板,其模板参数独立于类模板参数,但在定义成员模板时遇到了问题。 我将问题简化为尝试编译此文件(抱歉,无法进一步简化): 在尝试编译(C 11)时,我遇到以下错误: 我很确定它归结为第一个和第五个错误,但不知道我做错了什么。为什么

  • 我有一个模板化的C++类,它也有一个模板化的成员函数。这个成员函数的模板参数以特定的方式依赖于类的模板参数(请参阅下面的代码)。我正在为其模板参数的两个不同值实例化(而不是专门化)该类。一切都在这一点上进行。但是,如果我调用模板化的成员函数,对第一个实例化对象的调用只会编译,而不会编译第二个。似乎编译器没有为模板类的第二次实例化实例化模板化成员函数。我正在使用“g++filename.cpp”编译

  • 我很难弄清楚如何使用适当的模板化参数调用setValue函数。在ParameterBase抽象基类中不可能有模板化的参数。非常感谢任何帮助。 附注。我没有使用boost::any的灵活性。

  • 正如我们已经描述过的,模板可以使用在数据模型中定义的变量。 在数据模型之外,模板本身也可以定义变量来使用。 这些临时变量可以使用FTL指令来创建和替换。请注意每一次的 模板执行 工作都维护它自己的私有变量, 同时来渲染页面。变量的初始值是空,当模板执行工作结束这些变量便被销毁了。 可以访问一个在模板里定义的变量,就像是访问数据模型根root上的变量一样。 这个变量比定义在数据模型中的同名参数有更高

  • 我试图重写模板类http://docs.ros.org/hydro/api/rviz/html/c/message__filter__display_8h_source.html使用多种消息类型,使用变量模板。 我的第一个问题是如何使用可变模板重写下面的示例代码,以便它可以用于任意数量的模板参数,而不仅仅是2个。 我需要在家长类: 每个模板类型的虚拟成员函数 每个模板类型的每个的成员函数 每个模板

  • 在C++11之前,类模板和函数模板只能含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。 可变参数模板 可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号...: template<ty