在 class 模板的可变函数模板上使用 decltype 定义成员变量
Defining member variable using decltype on variadic function template of a class template
我正在尝试在可变函数模板上使用 'decltype' 来获取其 return 值类型,然后使用它来定义成员变量。但我不断收到此错误:
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
的 return 类型。
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;
};
当我提供 createDistribution
的所有参数值时它起作用,但这不是我正在寻找的行为。因为我不知道该函数会有多少参数,所以它必须保留为可变参数模板函数。
我打算如何使用 class 模板的示例:
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);
如果我没有任何成员变量并使用distributedTuple
作为:
auto distributionTuple = createDistribution<Type, Types...>(meanValue, meanValues..., varianceValue, varianceValues...);
它编译,因此我相信 createDistribution
设法递归定义元组。但这对我没有用。一定有什么地方错了,我想念的。
我在 -std=c++14 模式下使用 GCC 4.9.2。
当您需要在未计算的上下文中构建函数的完整调用时,请使用 std::declval
。使用它,您可以像这样声明 distributionTuple
:
decltype (std::declval<ParticleAttributeGenerator>().createDistribution<Type, Types...>(std::declval<Type>(), std::declval<Types>()..., std::declval<Type>(), std::declval<Types>()...)) distributionTuple;
首先,让我们将示例大幅简化为更易于管理且外部内容更少的内容:
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<int>
转换为 int
。那是因为:
foo<T>(T, T)
不是有效的函数调用。您需要使用具有这些类型的 表达式 调用 foo<T>
。不仅仅是类型列表。为此,我们有 std::declval
。即:
foo<T>(std::declval<T>(), std::declval<T>())
一旦你做了这个改变,你会得到一个新的编译错误:"cannot call member function foo
without object." 所以让我们再次添加一个带有 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;
};
我正在尝试在可变函数模板上使用 'decltype' 来获取其 return 值类型,然后使用它来定义成员变量。但我不断收到此错误:
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
的 return 类型。
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;
};
当我提供 createDistribution
的所有参数值时它起作用,但这不是我正在寻找的行为。因为我不知道该函数会有多少参数,所以它必须保留为可变参数模板函数。
我打算如何使用 class 模板的示例:
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);
如果我没有任何成员变量并使用distributedTuple
作为:
auto distributionTuple = createDistribution<Type, Types...>(meanValue, meanValues..., varianceValue, varianceValues...);
它编译,因此我相信 createDistribution
设法递归定义元组。但这对我没有用。一定有什么地方错了,我想念的。
我在 -std=c++14 模式下使用 GCC 4.9.2。
当您需要在未计算的上下文中构建函数的完整调用时,请使用 std::declval
。使用它,您可以像这样声明 distributionTuple
:
decltype (std::declval<ParticleAttributeGenerator>().createDistribution<Type, Types...>(std::declval<Type>(), std::declval<Types>()..., std::declval<Type>(), std::declval<Types>()...)) distributionTuple;
首先,让我们将示例大幅简化为更易于管理且外部内容更少的内容:
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<int>
转换为 int
。那是因为:
foo<T>(T, T)
不是有效的函数调用。您需要使用具有这些类型的 表达式 调用 foo<T>
。不仅仅是类型列表。为此,我们有 std::declval
。即:
foo<T>(std::declval<T>(), std::declval<T>())
一旦你做了这个改变,你会得到一个新的编译错误:"cannot call member function foo
without object." 所以让我们再次添加一个带有 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;
};