With reference to #4950.
--- /dev/null
+Changed: Specialization of the ProductType class are now implemented through
+specialization of the class internal::ProductTypeImpl . This was done in order
+to ensure that product operations performed with qualified number types do not
+result in the intended specializations being overlooked by the compiler.
+<br>
+(Jean-Paul Pelteret, Wolfgang Bangerth, 2017/08/24)
+namespace internal
+{
+
+ /**
+ * A struct that implements the default product type resulting from the
+ * multiplication of two types.
+ *
+ * @note Care should be taken when @p T or @p U have qualifiers (@p const or
+ * @p volatile) or are @p lvalue or @p rvalue references! It is recommended
+ * that specialization of this class is only made for unqualified (fully
+ * stripped) types and that the ProductType class be used to determine the
+ * result of operating with (potentially) qualified types.
+ *
+ * @author Wolfgang Bangerth, Jean-Paul Pelteret, 2017
+ */
+ template <typename T, typename U>
+ struct ProductTypeImpl
+ {
+ typedef decltype(std::declval<T>() * std::declval<U>()) type;
+ };
+
+}
+
+
+
/**
* A class with a local typedef that represents the type that results from the
* product of two variables of type @p T and @p U. In other words, we would
* used for the result of computing the product of unknowns and the values,
* gradients, or other properties of shape functions.
*
- * @author Wolfgang Bangerth, 2015
+ * @author Wolfgang Bangerth, 2015, 2017
*/
template <typename T, typename U>
struct ProductType
{
- typedef decltype(std::declval<T>() * std::declval<U>()) type;
+ typedef typename internal::ProductTypeImpl<
+ typename std::decay<T>::type, typename std::decay<U>::type>::type type;
};
-// Annoyingly, there is no std::complex<T>::operator*(U) for scalars U
-// other than T (not even in C++11, or C++14). We provide our own overloads
-// in base/complex_overloads.h, but in order for them to work, we have to
-// manually specify all products we want to allow:
-
-template <typename T>
-struct ProductType<std::complex<T>,std::complex<T> >
+namespace internal
{
- typedef std::complex<T> type;
-};
-template <typename T, typename U>
-struct ProductType<std::complex<T>,std::complex<U> >
-{
- typedef std::complex<typename ProductType<T,U>::type> type;
-};
+ // Annoyingly, there is no std::complex<T>::operator*(U) for scalars U
+ // other than T (not even in C++11, or C++14). We provide our own overloads
+ // in base/complex_overloads.h, but in order for them to work, we have to
+ // manually specify all products we want to allow:
-template <typename U>
-struct ProductType<double,std::complex<U> >
-{
- typedef std::complex<typename ProductType<double,U>::type> type;
-};
+ template <typename T>
+ struct ProductTypeImpl<std::complex<T>,std::complex<T> >
+ {
+ typedef std::complex<T> type;
+ };
-template <typename T>
-struct ProductType<std::complex<T>,double>
-{
- typedef std::complex<typename ProductType<T,double>::type> type;
-};
+ template <typename T, typename U>
+ struct ProductTypeImpl<std::complex<T>,std::complex<U> >
+ {
+ typedef std::complex<typename ProductType<T,U>::type> type;
+ };
-template <typename U>
-struct ProductType<float,std::complex<U> >
-{
- typedef std::complex<typename ProductType<float,U>::type> type;
-};
+ template <typename U>
+ struct ProductTypeImpl<double,std::complex<U> >
+ {
+ typedef std::complex<typename ProductType<double,U>::type> type;
+ };
-template <typename T>
-struct ProductType<std::complex<T>,float>
-{
- typedef std::complex<typename ProductType<T,float>::type> type;
-};
+ template <typename T>
+ struct ProductTypeImpl<std::complex<T>,double>
+ {
+ typedef std::complex<typename ProductType<T,double>::type> type;
+ };
+
+ template <typename U>
+ struct ProductTypeImpl<float,std::complex<U> >
+ {
+ typedef std::complex<typename ProductType<float,U>::type> type;
+ };
+
+ template <typename T>
+ struct ProductTypeImpl<std::complex<T>,float>
+ {
+ typedef std::complex<typename ProductType<T,float>::type> type;
+ };
+
+}
DEAL_II_NAMESPACE_OPEN
-template <typename T>
-struct ProductType<Sacado::Fad::DFad<T>, float>
-{
- typedef Sacado::Fad::DFad<T> type;
-};
-
-template <typename T>
-struct ProductType<float, Sacado::Fad::DFad<T> >
-{
- typedef Sacado::Fad::DFad<T> type;
-};
-
-template <typename T>
-struct ProductType<Sacado::Fad::DFad<T>, double>
-{
- typedef Sacado::Fad::DFad<T> type;
-};
-
-template <typename T>
-struct ProductType<double, Sacado::Fad::DFad<T> >
+namespace internal
{
- typedef Sacado::Fad::DFad<T> type;
-};
-template <typename T>
-struct ProductType<Sacado::Fad::DFad<T>, int>
-{
- typedef Sacado::Fad::DFad<T> type;
-};
+ template <typename T>
+ struct ProductTypeImpl<Sacado::Fad::DFad<T>, float>
+ {
+ typedef Sacado::Fad::DFad<T> type;
+ };
+
+ template <typename T>
+ struct ProductTypeImpl<float, Sacado::Fad::DFad<T> >
+ {
+ typedef Sacado::Fad::DFad<T> type;
+ };
+
+ template <typename T>
+ struct ProductTypeImpl<Sacado::Fad::DFad<T>, double>
+ {
+ typedef Sacado::Fad::DFad<T> type;
+ };
+
+ template <typename T>
+ struct ProductTypeImpl<double, Sacado::Fad::DFad<T> >
+ {
+ typedef Sacado::Fad::DFad<T> type;
+ };
+
+ template <typename T>
+ struct ProductTypeImpl<Sacado::Fad::DFad<T>, int>
+ {
+ typedef Sacado::Fad::DFad<T> type;
+ };
+
+ template <typename T>
+ struct ProductTypeImpl<int, Sacado::Fad::DFad<T> >
+ {
+ typedef Sacado::Fad::DFad<T> type;
+ };
+
+ template <typename T, typename U>
+ struct ProductTypeImpl<Sacado::Fad::DFad<T>, Sacado::Fad::DFad<U> >
+ {
+ typedef Sacado::Fad::DFad<typename ProductType<T,U>::type > type;
+ };
-template <typename T>
-struct ProductType<int, Sacado::Fad::DFad<T> >
-{
- typedef Sacado::Fad::DFad<T> type;
-};
-
-template <typename T, typename U>
-struct ProductType<Sacado::Fad::DFad<T>, Sacado::Fad::DFad<U> >
-{
- typedef Sacado::Fad::DFad<typename ProductType<T,U>::type > type;
-};
+}
template <typename T>
struct EnableIfScalar<Sacado::Fad::DFad<T> >
* A typedef for the data type of the product of a @p Number and the
* values of the view the Scalar class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Scalar<dim,spacedim>::value_type>::type value_type;
+ typedef typename ProductType<Number, typename Scalar<dim,spacedim>::value_type>::type value_type;
/**
* A typedef for the data type of the product of a @p Number and the
* gradients of the view the Scalar class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Scalar<dim,spacedim>::gradient_type>::type gradient_type;
+ typedef typename ProductType<Number, typename Scalar<dim,spacedim>::gradient_type>::type gradient_type;
/**
* A typedef for the data type of the product of a @p Number and the
* laplacians of the view the Scalar class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Scalar<dim,spacedim>::value_type>::type laplacian_type;
+ typedef typename ProductType<Number, typename Scalar<dim,spacedim>::value_type>::type laplacian_type;
/**
* A typedef for the data type of the product of a @p Number and the
* hessians of the view the Scalar class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Scalar<dim,spacedim>::hessian_type>::type hessian_type;
+ typedef typename ProductType<Number, typename Scalar<dim,spacedim>::hessian_type>::type hessian_type;
/**
* A typedef for the data type of the product of a @p Number and the
* third derivatives of the view the Scalar class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Scalar<dim,spacedim>::third_derivative_type>::type third_derivative_type;
+ typedef typename ProductType<Number, typename Scalar<dim,spacedim>::third_derivative_type>::type third_derivative_type;
};
/**
* A typedef for the data type of the product of a @p Number and the
* values of the view the Vector class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Vector<dim,spacedim>::value_type>::type value_type;
+ typedef typename ProductType<Number, typename Vector<dim,spacedim>::value_type>::type value_type;
/**
* A typedef for the data type of the product of a @p Number and the
* gradients of the view the Vector class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Vector<dim,spacedim>::gradient_type>::type gradient_type;
+ typedef typename ProductType<Number, typename Vector<dim,spacedim>::gradient_type>::type gradient_type;
/**
* A typedef for the data type of the product of a @p Number and the
* symmetric gradients of the view the Vector class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Vector<dim,spacedim>::symmetric_gradient_type>::type symmetric_gradient_type;
+ typedef typename ProductType<Number, typename Vector<dim,spacedim>::symmetric_gradient_type>::type symmetric_gradient_type;
/**
* A typedef for the data type of the product of a @p Number and the
* divergences of the view the Vector class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Vector<dim,spacedim>::divergence_type>::type divergence_type;
+ typedef typename ProductType<Number, typename Vector<dim,spacedim>::divergence_type>::type divergence_type;
/**
* A typedef for the data type of the product of a @p Number and the
* laplacians of the view the Vector class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Vector<dim,spacedim>::value_type>::type laplacian_type;
+ typedef typename ProductType<Number, typename Vector<dim,spacedim>::value_type>::type laplacian_type;
/**
* A typedef for the data type of the product of a @p Number and the
* curls of the view the Vector class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Vector<dim,spacedim>::curl_type>::type curl_type;
+ typedef typename ProductType<Number, typename Vector<dim,spacedim>::curl_type>::type curl_type;
/**
* A typedef for the data type of the product of a @p Number and the
* hessians of the view the Vector class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Vector<dim,spacedim>::hessian_type>::type hessian_type;
+ typedef typename ProductType<Number, typename Vector<dim,spacedim>::hessian_type>::type hessian_type;
/**
* A typedef for the data type of the product of a @p Number and the
* third derivatives of the view the Vector class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Vector<dim,spacedim>::third_derivative_type>::type third_derivative_type;
+ typedef typename ProductType<Number, typename Vector<dim,spacedim>::third_derivative_type>::type third_derivative_type;
};
/**
* A typedef for the data type of the product of a @p Number and the
* values of the view the SymmetricTensor class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename SymmetricTensor<2,dim,spacedim>::value_type>::type value_type;
+ typedef typename ProductType<Number, typename SymmetricTensor<2,dim,spacedim>::value_type>::type value_type;
/**
* A typedef for the data type of the product of a @p Number and the
* divergences of the view the SymmetricTensor class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename SymmetricTensor<2,dim,spacedim>::divergence_type>::type divergence_type;
+ typedef typename ProductType<Number, typename SymmetricTensor<2,dim,spacedim>::divergence_type>::type divergence_type;
};
/**
* A typedef for the data type of the product of a @p Number and the
* values of the view the Tensor class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Tensor<2,dim,spacedim>::value_type>::type value_type;
+ typedef typename ProductType<Number, typename Tensor<2,dim,spacedim>::value_type>::type value_type;
/**
* A typedef for the data type of the product of a @p Number and the
* divergences of the view the Tensor class.
*/
- typedef typename ProductType<typename std::decay<Number>::type, typename Tensor<2,dim,spacedim>::divergence_type>::type divergence_type;
+ typedef typename ProductType<Number, typename Tensor<2,dim,spacedim>::divergence_type>::type divergence_type;
};
/**
do_function_values (const ArrayView<Number> &dof_values,
const Table<2,double> &shape_values,
const std::vector<typename Scalar<dim,spacedim>::ShapeFunctionData> &shape_function_data,
- std::vector<typename ProductType<typename std::decay<Number>::type,double>::type> &values)
+ std::vector<typename ProductType<Number,double>::type> &values)
{
const unsigned int dofs_per_cell = dof_values.size();
const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
shape_values.n_cols() : values.size();
AssertDimension (values.size(), n_quadrature_points);
- std::fill (values.begin(), values.end(), dealii::internal::NumberType<typename std::decay<Number>::type>::value(0.0));
+ std::fill (values.begin(), values.end(),
+ dealii::internal::NumberType<typename std::decay<Number>::type>::value(0.0));
for (unsigned int shape_function=0;
shape_function<dofs_per_cell; ++shape_function)
do_function_derivatives (const ArrayView<Number> &dof_values,
const Table<2,dealii::Tensor<order,spacedim> > &shape_derivatives,
const std::vector<typename Scalar<dim,spacedim>::ShapeFunctionData> &shape_function_data,
- std::vector<typename ProductType<typename std::decay<Number>::type,dealii::Tensor<order,spacedim> >::type> &derivatives)
+ std::vector<typename ProductType<Number,dealii::Tensor<order,spacedim> >::type> &derivatives)
{
const unsigned int dofs_per_cell = dof_values.size();
const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
AssertDimension (derivatives.size(), n_quadrature_points);
std::fill (derivatives.begin(), derivatives.end(),
- typename ProductType<typename std::decay<Number>::type,dealii::Tensor<order,spacedim> >::type());
+ typename ProductType<Number,dealii::Tensor<order,spacedim> >::type());
for (unsigned int shape_function=0;
shape_function<dofs_per_cell; ++shape_function)
void do_function_values (const ArrayView<Number> &dof_values,
const Table<2,double> &shape_values,
const std::vector<typename Vector<dim,spacedim>::ShapeFunctionData> &shape_function_data,
- std::vector<typename ProductType<typename std::decay<Number>::type,dealii::Tensor<1,spacedim> >::type> &values)
+ std::vector<typename ProductType<Number,dealii::Tensor<1,spacedim> >::type> &values)
{
const unsigned int dofs_per_cell = dof_values.size();
const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
shape_values.n_cols() : values.size();
AssertDimension (values.size(), n_quadrature_points);
- std::fill (values.begin(), values.end(), typename ProductType<typename std::decay<Number>::type,dealii::Tensor<1,spacedim> >::type());
+ std::fill (values.begin(), values.end(),
+ typename ProductType<Number,dealii::Tensor<1,spacedim> >::type());
for (unsigned int shape_function=0;
shape_function<dofs_per_cell; ++shape_function)
do_function_derivatives (const ArrayView<Number> &dof_values,
const Table<2,dealii::Tensor<order,spacedim> > &shape_derivatives,
const std::vector<typename Vector<dim,spacedim>::ShapeFunctionData> &shape_function_data,
- std::vector<typename ProductType<typename std::decay<Number>::type,dealii::Tensor<order+1,spacedim> >::type> &derivatives)
+ std::vector<typename ProductType<Number,dealii::Tensor<order+1,spacedim> >::type> &derivatives)
{
const unsigned int dofs_per_cell = dof_values.size();
const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
AssertDimension (derivatives.size(), n_quadrature_points);
std::fill (derivatives.begin(), derivatives.end(),
- typename ProductType<typename std::decay<Number>::type,dealii::Tensor<order+1,spacedim> >::type());
+ typename ProductType<Number,dealii::Tensor<order+1,spacedim> >::type());
for (unsigned int shape_function=0;
shape_function<dofs_per_cell; ++shape_function)
do_function_symmetric_gradients (const ArrayView<Number> &dof_values,
const Table<2,dealii::Tensor<1,spacedim> > &shape_gradients,
const std::vector<typename Vector<dim,spacedim>::ShapeFunctionData> &shape_function_data,
- std::vector<typename ProductType<typename std::decay<Number>::type,dealii::SymmetricTensor<2,spacedim> >::type> &symmetric_gradients)
+ std::vector<typename ProductType<Number,dealii::SymmetricTensor<2,spacedim> >::type> &symmetric_gradients)
{
const unsigned int dofs_per_cell = dof_values.size();
const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
AssertDimension (symmetric_gradients.size(), n_quadrature_points);
std::fill (symmetric_gradients.begin(), symmetric_gradients.end(),
- typename ProductType<typename std::decay<Number>::type,dealii::SymmetricTensor<2,spacedim> >::type());
+ typename ProductType<Number,dealii::SymmetricTensor<2,spacedim> >::type());
for (unsigned int shape_function=0;
shape_function<dofs_per_cell; ++shape_function)
do_function_curls (const ArrayView<Number> &dof_values,
const Table<2,dealii::Tensor<1,spacedim> > &shape_gradients,
const std::vector<typename Vector<dim,spacedim>::ShapeFunctionData> &shape_function_data,
- std::vector<typename ProductType<typename std::decay<Number>::type,typename dealii::internal::CurlType<spacedim>::type>::type> &curls)
+ std::vector<typename ProductType<Number,typename dealii::internal::CurlType<spacedim>::type>::type> &curls)
{
const unsigned int dofs_per_cell = dof_values.size();
const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
AssertDimension (curls.size(), n_quadrature_points);
std::fill (curls.begin(), curls.end(),
- typename ProductType<typename std::decay<Number>::type,typename dealii::internal::CurlType<spacedim>::type>::type());
+ typename ProductType<Number,typename dealii::internal::CurlType<spacedim>::type>::type());
switch (spacedim)
{
do_function_values (const ArrayView<Number> &dof_values,
const dealii::Table<2,double> &shape_values,
const std::vector<typename SymmetricTensor<2,dim,spacedim>::ShapeFunctionData> &shape_function_data,
- std::vector<typename ProductType<typename std::decay<Number>::type,dealii::SymmetricTensor<2,spacedim> >::type> &values)
+ std::vector<typename ProductType<Number,dealii::SymmetricTensor<2,spacedim> >::type> &values)
{
const unsigned int dofs_per_cell = dof_values.size();
const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
AssertDimension (values.size(), n_quadrature_points);
std::fill (values.begin(), values.end(),
- typename ProductType<typename std::decay<Number>::type,dealii::SymmetricTensor<2,spacedim> >::type());
+ typename ProductType<Number,dealii::SymmetricTensor<2,spacedim> >::type());
for (unsigned int shape_function=0;
shape_function<dofs_per_cell; ++shape_function)
do_function_values (const ArrayView<Number> &dof_values,
const dealii::Table<2,double> &shape_values,
const std::vector<typename Tensor<2,dim,spacedim>::ShapeFunctionData> &shape_function_data,
- std::vector<typename ProductType<typename std::decay<Number>::type,dealii::Tensor<2,spacedim> >::type> &values)
+ std::vector<typename ProductType<Number,dealii::Tensor<2,spacedim> >::type> &values)
{
const unsigned int dofs_per_cell = dof_values.size();
const unsigned int n_quadrature_points = dofs_per_cell > 0 ?
AssertDimension (values.size(), n_quadrature_points);
std::fill (values.begin(), values.end(),
- typename ProductType<typename std::decay<Number>::type,dealii::Tensor<2,spacedim> >::type());
+ typename ProductType<Number,dealii::Tensor<2,spacedim> >::type());
for (unsigned int shape_function=0;
shape_function<dofs_per_cell; ++shape_function)
AssertDimension(values.size(), n_quadrature_points);
// initialize with zero
- std::fill_n (values.begin(), n_quadrature_points, dealii::internal::NumberType<typename std::decay<Number>::type>::value(0.0));
+ std::fill_n (values.begin(), n_quadrature_points,
+ dealii::internal::NumberType<typename std::decay<Number>::type>::value(0.0));
// add up contributions of trial functions. note that here we deal with
// scalar finite elements, so no need to check for non-primitivity of
AssertDimension(laplacians.size(), n_quadrature_points);
// initialize with zero
- std::fill_n (laplacians.begin(), n_quadrature_points, dealii::internal::NumberType<typename std::decay<Number>::type>::value(0.0));
+ std::fill_n (laplacians.begin(), n_quadrature_points,
+ dealii::internal::NumberType<typename std::decay<Number>::type>::value(0.0));
// add up contributions of trial functions. note that here we deal with
// scalar finite elements and also note that the Laplacian is