Error: Incomplete templated type - c++
I am having an issue using an incomplete templated type. I have searched quite a while for a solution but every answer I have found has tended to be along the lines of "include the header," "forward declare," or "you can't do that with STL." I have a feeling that I am looking for the wrong thing or that the first dozen pages of Google are flooded
While I definitely am looking for a fix, I would very much appreciate an explanation, or perhaps a link to a good guide. I am fairly new to heavily templated OOP and would love to learn what is wrong, how it is wrong and why.
So I am going to attempt to include AS MUCH code as possible without giving you guys multiple 500 line files. Ellipses are where I removed code that has nothing to do with this issue (or where I removed other direction iterations and larger stencils). Also, SpatialOps is the library we use for spatial operations. Everything links fine, everything compiles fine via CMake, etc, if I remove the code that I am posting here.
Starting with the error message:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp: In function ‘void LBMS::build_operators(const BundlePtr&)’:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:154:96: error: invalid use of incomplete type ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus ) );
^
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:6:0,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:1:
/scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:115:10: error: declaration of ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
struct OneSidedOpTypeBuilder;
Here is the offending header file in LBMS (our code base). Operators.h =>
#ifndef LBMSOperators_h
#define LBMSOperators_h
#include <spatialops/structured/stencil/FVStaggeredBCOp.h>
#include <spatialops/structured/stencil/FVStaggeredOperatorTypes.h>
#include <spatialops/structured/stencil/OneSidedOperatorTypes.h>
...
#include <spatialops/structured/stencil/StencilBuilder.h>
#include <spatialops/Nebo.h>
/**
* \file Operators.h
* \brief Defines operators for use in LBMS.
*/
namespace SpatialOps{
class OperatorDatabase; // forward declaration
}
namespace SpatialOps{
...
typedef SpatialOps::OneSidedStencil2< SpatialOps::UnitTriplet<SpatialOps::XDIR>::type > X2PlusT;
typedef SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, X2PlusT, LBMS::XVolField> X2PosX;
...
} // namespace SpatialOps
#endif // LBMSOperators_h
And its corresponding cpp file. Operators.cpp =>
#include "Operators.h"
...
//--- SpatialOps Headers ---//
#include <spatialops/OperatorDatabase.h>
#include <spatialops/structured/stencil/StencilBuilder.h>
#include <spatialops/Nebo.h>
using namespace SpatialOps;
...
namespace LBMS{
...
void
build_operators( const BundlePtr& bundle )
{
SpatialOps::OperatorDatabase& opDB = bundle->operator_database();
const double dx = bundle->spacing(XDIR);
NeboStencilCoefCollection<2> coefHalfDx2Plus = build_two_point_coef_collection( -1.0/dx, 1.0/dx );
...
opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus ) );
...
}
} // namespace LBMS
This is the header from the library that contains the operators that I am trying to utilize (again, in LBMS). OneSidedOperatorTypes.h =>
#ifndef SpatialOps_structured_OneSidedOpTypes_h
#define SpatialOps_structured_OneSidedOpTypes_h
#include <spatialops/SpatialOpsDefs.h>
#include <spatialops/Nebo.h>
namespace SpatialOps{
template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >
class OneSidedOpTypeBuilder; // forward declaration
}
/**
* \struct OneSidedStencil2
* \brief Support for one-sided stencils.
* \tparam OpDir the unit vector (a IndexTriplet) that indicates the direction of offset for the stencil.
* \tparam Offset (optional) the offset for the stencil. <0,0,0> (default) results in a
* one-sided stencil that computes into the first stencil point.
* <1,0,0> would offset the stencil so that it effectively computes
* into the <-1,0,0> point.
*
* \par Example:
* This code describes a 2-point stencil oriented in the (+x) direction.
* \code{.cpp}
* OneSidedStencil2< IndexTriplet<1,0,0> >
* \endcode
* It would look something like this:
* \verbatim
1 2 3
Read : o o o
Write: o
\endverbatim
*
* \par Example:
* This code describes a 2-point stencil oriented in the (-x) direction that
* is offset in the (-x) direction.
* \code{.cpp}
* OneSidedStencil2< IndexTriplet<-1,0,0>, IndexTriplet<-1,0,0> >
* \endcode
* It would look something like this:
* \verbatim
n-2 n-1 n
Read : o o
Write: o
\endverbatim
*/
template<typename OpDir, typename Offset=IndexTriplet<0,0,0> >
struct OneSidedStencil2{
typedef OpDir DirT; ///< The orientation of the stencil (IndexTriplet)
typedef typename Add<Offset,OpDir>::result Point2;
typedef NEBO_FIRST_POINT(Offset)::NEBO_ADD_POINT(Point2) StPtCollection;
};
...
/**
* \struct OneSidedOpTypeBuilder
* \ingroup optypes
* \brief Builds OneSidedDiv operator type from field type.
*
* \tparam Op the basic operator type (e.g., Gradient, Interpolant)
* \tparam StencilT the stencil structure (e.g., OneSidedStencil3<IndexTriplet<0,-1,0>)
* \tparam FieldT the field that the operator applies to (e.g., SVolField)
* \tparam Offset the offset for the stencil. <0,0,0> (default) results in a
* one-sided stencil that computes into the first stencil point.
* <1,0,0> would offset the stencil so that it effectively computes
* into the <-1,0,0> point.
*
* \par Example Usage
* The following obtains the full type for a two-point, one-sided stencil
* shifted in the (-z) direction:
* \code
* typedef UnitTriplet<ZDIR>::type::Negate ZMinus;
* typedef OneSidedOpTypeBuilder<Gradient,OneSidedStencil2<ZMinus>,SVolField>::type OneSidedDiv2Z;
* \endcode
*
* Note that we only provide fully specialized versions of this template
* so that unsupported operator types cannot be inadvertently formed.
*/
template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >
struct OneSidedOpTypeBuilder;
#define BUILD_ONE_SIDED_OP_ACROSS_DIRS( Op, I1, I2, I3, StencilT, FieldT ) \
template<> struct OneSidedOpTypeBuilder<Op,StencilT<IndexTriplet<I1,I2,I3> >,FieldT>{ \
typedef NeboStencilBuilder<Op,StencilT<IndexTriplet<I1,I2,I3> >::StPtCollection, FieldT, FieldT> type; \
};
#define ONE_SIDED_OP_BUILDERS( Op, I1, I2, I3, FieldT ) \
BUILD_ONE_SIDED_OP_ACROSS_DIRS( Op, I1, I2, I3, OneSidedStencil2, FieldT ) \
...
#define BUILD_ONE_SIDED_STENCILS( FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 1, 0, 0, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, -1, 0, 0, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 0, 1, 0, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 0,-1, 0, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 0, 0, 1, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 0, 0,-1, FieldT )
...
BUILD_ONE_SIDED_STENCILS( XVolField )
...
} // namespace SpatialOps
#endif // SpatialOps_structured_OneSidedOpTypes_h
If I forward declare in the Operators.h, such as
namespace SpatialOps{
template<typename Op, typename StencilT, typename FieldT>
struct OneSidedOpTypeBuilder; // forward declaration
}
then I see the following error message:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:28:9: error: redefinition of default argument for ‘class Offset’
class OneSidedOpTypeBuilder; // forward declaration
Or if I include the default template argument in the forward declare in Operators.h,
I get the following error:
[ 30%] Building CXX object src/CMakeFiles/lbms.dir/lbms/ProblemSolver.cpp.o
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/transport/TransportEquationBase.h:40:0,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.h:38,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.cpp:29:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:28:10: error: redefinition of default argument for ‘class Offset’
struct OneSidedOpTypeBuilder; // forward declaration
^
In file included from /scratch/local/prism_large/dac/debugging/nscbcbuild/include/nscbc/NSCBCToolsAndDefs.h:18:0,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/BCOptions.h:43,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.h:30,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.cpp:29:
/scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:114:61: note: original definition appeared here
template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >
Or if I do not include the default template argument, I am back to the beginning with:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp: In function ‘void LBMS::build_operators(const BundlePtr&)’:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:154:96: error: invalid use of incomplete type ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus ) );
^
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:6:0,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:1:
/scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:115:10: error: declaration of ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
struct OneSidedOpTypeBuilder;
^
Please let me know if there is anything else I should include. On one hand, I very well understand the importance of including everything but on the other, some of these libraries are quite large.
Thanks a bunch!
Searching on the web for your OneSidedOpTypeBuilder class I found the header file where it's defined. If you look in that file you'll see below the forward reference that there is a preprocessor macro for creating template specializations.
#define ONE_SIDED_OP_BUILDER( OP, STYLE, FIELD ) \
template<> \
struct OneSidedOpTypeBuilder<OP,FIELD>{ \
typedef NeboStencilBuilder<OP, \
STYLE<OP,FIELD>::StPtCollection, \
FIELD, \
FIELD> \
type; \
};
I believe you're using OneSidedOpTypeBuilder incorrectly and need to do something like
ONE_SIDED_OP_BUILDER(SpatialOps::Gradient, X2PlusT, LBMS::XVolField);
before the typedef for your X2PosX type.
Related
Using boost::geometry::index::indexable within an IndexableGetter in Windows
Building on top of this example: https://www.boost.org/doc/libs/1_75_0/libs/geometry/doc/html/geometry/spatial_indexes/rtree_examples/using_indexablegetter_function_object___storing_indexes_of_external_container_s_elements.html I have constructed the following MWE to build and query spatial trees based on indices onto non-trivial containers. The example this was based upon assumes that Container::value_type is already a leaf of the tree. I simply adapted the example to work with any indexable type, i.e., any type understood by bgi::indexable<typename Container::value_type>. The included MWE works just fine on Linux and Mac, but fails to compile on Windows, and I'm struggling in understanding what the problem may be. A working example is here https://godbolt.org/z/vTT5r5MWc, where you can see that if you switch to gcc or clang, everything works, but with MSVC19 we get the errors reported below. Any idea on how to modify the IndexableGetter/anything else to make this work under MSVC? #include <boost/geometry/index/rtree.hpp> #include <boost/geometry/strategies/strategies.hpp> #include <boost/range/irange.hpp> #include <iostream> namespace bg = boost::geometry; namespace bgi = boost::geometry::index; template <typename LeafType, typename IndexType = bgi::linear<16>, typename IndexableGetter = bgi::indexable<LeafType>> using RTree = bgi::rtree<LeafType, IndexType, IndexableGetter>; using Point = bg::model::point<double, 2, bg::cs::cartesian>; template <typename Container> class IndexableGetterFromIndices { public: using IndexableGetter = typename bgi::indexable<typename Container::value_type>; using result_type = typename IndexableGetter::result_type; using size_t = typename Container::size_type; explicit IndexableGetterFromIndices(Container const &c) : container(c) {} result_type operator()(size_t i) const { return getter(container[i]); } private: const Container &container; IndexableGetter getter; }; template <typename IndexType = boost::geometry::index::linear<16>, typename ContainerType> RTree<typename ContainerType::size_type, IndexType, IndexableGetterFromIndices<ContainerType>> pack_rtree_of_indices(const ContainerType &container) { boost::integer_range<typename ContainerType::size_type> indices( 0, container.size()); return RTree<typename ContainerType::size_type, IndexType, IndexableGetterFromIndices<ContainerType>>( indices.begin(), indices.end(), IndexType(), IndexableGetterFromIndices<ContainerType>(container)); } int main() { std::vector<std::pair<Point, int>> points; // create some points for (unsigned i = 0; i < 10; ++i) points.push_back(std::make_pair(Point(i + 0.0, i + 0.0), i * 10)); const auto tree = pack_rtree_of_indices(points); for (const auto result : tree | bgi::adaptors::queried(bgi::nearest(Point(3.0, 4.0), 1))) { std::cout << "Nearest point: " << bg::wkt<Point>(points[result].first) << ", index = " << points[result].second << std::endl; } } The error I get on Windows is example.cpp C:/data/libraries/installed/x64-windows/include\boost/geometry/index/rtree.hpp(1762): error C2664: 'boost::geometry::index::detail::translator<IndexableGetter,EqualTo>::translator(const boost::geometry::index::indexable<std::pair<Point,int>> &,const EqualTo &)': cannot convert argument 1 from 'const IndGet' to 'const boost::geometry::index::indexable<std::pair<Point,int>> &' with [ IndexableGetter=IndexableGetterFromIndices<std::vector<std::pair<Point,int>,std::allocator<std::pair<Point,int>>>>, EqualTo=boost::geometry::index::equal_to<std::_Default_allocator_traits<std::allocator<std::pair<Point,int>>>::size_type> ] and [ IndGet=IndexableGetterFromIndices<std::vector<std::pair<Point,int>,std::allocator<std::pair<Point,int>>>> ] C:/data/libraries/installed/x64-windows/include\boost/geometry/index/rtree.hpp(1768): note: Reason: cannot convert from 'const IndGet' to 'const boost::geometry::index::indexable<std::pair<Point,int>>' with [ IndGet=IndexableGetterFromIndices<std::vector<std::pair<Point,int>,std::allocator<std::pair<Point,int>>>> ] C:/data/libraries/installed/x64-windows/include\boost/geometry/index/rtree.hpp(1762): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called C:/data/libraries/installed/x64-windows/include\boost/geometry/index/detail/translator.hpp(51): note: see declaration of 'boost::geometry::index::detail::translator<IndexableGetter,EqualTo>::translator' with [ IndexableGetter=IndexableGetterFromIndices<std::vector<std::pair<Point,int>,std::allocator<std::pair<Point,int>>>>, EqualTo=boost::geometry::index::equal_to<std::_Default_allocator_traits<std::allocator<std::pair<Point,int>>>::size_type> ] ....
Thanks for a very neat self-contained example. It does compile with /std::latest: x86 msvc v19.latest, Live On Compiler Explorer). x64 msvc v19.latest, Live On Compiler Explorer). In retrospect there was the clue: cl : Command line warning D9002 : ignoring unknown option '-std=c++2a'
Eigen Tensor compilation error
I am experimenting with Eigen::Tensor, and I do not manage to understand why the most basic example is failing. Why does this piece of code #include <unsupported/Eigen/CXX11/Tensor> int main() { Eigen::Tensor<int, 2> a(4, 4); Eigen::Tensor<int, 2> b(4, 4); a.setRandom(); b.setRandom(); a += b; return 0; } results in error: In file included from eigen.cpp:2: In file included from /usr/local/include/eigen3/unsupported/Eigen/CXX11/Tensor:142: /usr/local/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h:39:7: error: class template partial specialization is not more specialized than the primary template [-Winvalid-partial-specialization] class TensorStorage<T, FixedDimensions, Options_> ^ /usr/local/include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h:34:63: note: template is declared here template<typename T, typename Dimensions, int Options_> class TensorStorage;
Please, update to the default branch (recommended for the Tensor module), or at least to the head of the 3.3 branch.
Combining Eigen and CppAD
I want to use automatic differentiation mechanism provided by CppAD inside Eigen linear algebra. An example type is Eigen::Matrix< CppAD::AD,-1,-1>. As CppAD::AD is a custom numeric type the NumTraits for this type have to be provided. CppAD provides those in the file cppad/example/cppad_eigen.hpp. This makes the following minimal example compile: #include <cppad/cppad.hpp> #include <cppad/example/cppad_eigen.hpp> int main() { typedef double Scalar; typedef CppAD::AD<Scalar> AD; // independent variable vector Eigen::Matrix<AD,Eigen::Dynamic,1> x(4); CppAD::Independent(x); // dependent variable vector Eigen::Matrix<AD,Eigen::Dynamic,1> y(4); Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> m(4,4); m.setIdentity(); y = 1. * x; // THIS DOES NOT WORK // y = m * x; CppAD::ADFun<Scalar> fun(x, y); } As soon as some more complex expression is used, e.g. the mentioned y = m * x; the code fails to compile: PATH/Eigen/latest/include/Eigen/src/Core/Product.h:29:116: error: no type named 'ReturnType' in 'Eigen::ScalarBinaryOpTraits<double, CppAD::AD<double>, Eigen::internal::scalar_product_op<double, CppAD::AD<double> > >' ...typename ScalarBinaryOpTraits<typename traits<LhsCleaned>::Scalar, typename traits<RhsCleaned>::Scalar>::ReturnType... If i manually cast the double Matrix to AD, it works. However this is not a solution because the type promotion is virtually used everywhere in Eigen. It looks to me as if the NumTraits provided by CppAD are not sufficient for this case. This is supported by a followup error message: PATH/Eigen/latest/include/Eigen/src/Core/Product.h:155:5: error: no type named 'CoeffReturnType' in 'Eigen::internal::dense_product_base<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<CppAD::AD<double>, -1, 1, 0, -1, 1>, 0, 7>' EIGEN_DENSE_PUBLIC_INTERFACE(Derived) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Other use cases lead to error messages like: PATH/Eigen/src/Core/functors/Binary Functors.h:78:92: error: no type named ‘ReturnType’ in ‘struct Eigen::ScalarBinaryOpTraits<dou ble, CppAD::AD<double>, Eigen::internal::scalar_product_op<double, CppAD::AD<double> > >’ Can anybody point me in the correct direction? It is possible that the NumTraits are for old Eigen Versions. I'm using 3.3.2 and CppAD from the current master branch.
If you want to multiply a Matrix<CppAD::AD<double>, ...> by a Matrix<double, ...> you also need to specialize the corresponding ScalarBinaryOpTraits: namespace Eigen { template<typename X, typename BinOp> struct ScalarBinaryOpTraits<CppAD::AD<X>,X,BinOp> { typedef CppAD::AD<X> ReturnType; }; template<typename X, typename BinOp> struct ScalarBinaryOpTraits<X,CppAD::AD<X>,BinOp> { typedef CppAD::AD<X> ReturnType; }; } // namespace Eigen This requires that CppAD::AD<X>() * X() is implemented. Alternatively, you need to cast your matrix m to AD: // should work: y = m.cast<CppAD::AD<double> >() * x;
Clang candidate template ignored: substitution failure (also fails to compile with gcc, VC works fine)
I am having an issue with Clang 3.5. The following is a self-contained repro. This code compiles with VC12. With Clang I get the following error: 1>C:\Users\jcuyle\code\branches\dev\ClientSDK\test\CompilerTestbed\CompilerTestbed.cpp(111,5): error : no matching function for call to 'out_from_storage' 1> }( util::out_from_storage( rv ) ); 1> ^~~~~~~~~~~~~~~~~~~~~~ 1> C:\Users\jcuyle\code\branches\dev\ClientSDK\test\CompilerTestbed\CompilerTestbed.cpp(37,13): note: candidate template ignored: substitution failure [with storage_t = std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<long, std::ratio<1, 1000000000> > > &]: no matching function for call to 'out_from_storage' 1> inline auto out_from_storage( storage_t && storage ) -> decltype( util::details::template out_from_storage( std::forward< storage_t >( storage ) ) ) 1> ^ ~~~~ 1> 1 error generated. Here's the code: #include <stdint.h> #include <type_traits> #include <chrono> #include <utility> namespace util { namespace details { template< typename RTy, typename Ty, typename enable = void > inline RTy out_from_storage( Ty ); template< typename Ty, typename = typename std::enable_if< std::is_trivial< typename std::decay< Ty >::type >::value, Ty >::type > inline typename std::add_pointer< typename std::decay< Ty >::type >::type out_from_storage( Ty&& t ) { return &t; } } // namespace details template< typename storage_t > inline auto out_from_storage( storage_t && storage ) -> decltype( util::details::out_from_storage( std::forward< storage_t >( storage ) ) ) { return util::details::out_from_storage( std::forward< storage_t >( storage ) ); } } // namespace util namespace util { namespace details { template< typename enable = void > inline int64_t out_from_storage( std::chrono::system_clock::time_point & storage ) { return std::chrono::system_clock::to_time_t( storage ); } } // namespace details } // namespace util int main(int argc, char * argv[]) { std::chrono::system_clock::time_point out = std::chrono::system_clock::now( ); util::out_from_storage( out ); // error util::details::out_from_storage( out ); // no error return 0; } While this example is fairly trivial, the code is a chunk of a utility library for marshaling types across a DLL boundary. There are a number of similar utility functions and a large number of specializations for different types. All works fine under VC, and I suspect there's just some bogus syntax that VC accepts but needs to be slightly more correct for Clang and gcc to accept. Significant reordering of the code is difficult, and major rewrites of the system to use a completely different approach to specializing the conversion functions (e.g. yanking out the type_traits/enable_if and using tag dispatch or similar) are impractical. If someone can explain why it is that Clang can't find the matching function call for util::details::out_from_storage( std::chrono::system_clock::time_point & storage ) even though it pretty clearly exists (and VC can find it) I'd really appreciate it. I'm very new to Clang and gcc. Thanks!
You have one overload of out_from_storage that is callable without explicitly providing template arguments, and it relies on: std::is_trivial< typename std::decay< Ty >::type >::value You're calling it with an instance of time_point, but that isn't a trivial type because it doesn't have a trivial default constructor. Hence, this overload is removed from the set. Since there is no viable overload, the call fails.
Custom allocator & default member
Why isn't this code compiling ? #include <cstdlib> #include <list> template < typename Type > class Allocator { public: using value_type = Type; public: template < typename Other > struct rebind { using other = Allocator< Other >; }; public: Type * allocate( std::size_t n ) { return std::malloc( n ); } void deallocate( Type * p, std::size_t ) throw ( ) { std::free( p ); } }; int main( void ) { std::list< void *, Allocator< void * > > list; return 0; } It seems to need pointer, reference, pointer_const & reference_const types. However, according to cppreference these members are all optionals. It seems like if the STL weren't using allocator_trait (I'm compiling with -std=c++11 so it should be good). Any idea ? [edit] On clang, errors are : user#/tmp > clang++ -std=c++11 test.cc In file included from test.cc:2: In file included from /usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/list:63: /usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/stl_list.h:449:40: error: no type named 'pointer' in 'Allocator<void *>' typedef typename _Tp_alloc_type::pointer pointer; ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~ test.cc:17:46: note: in instantiation of template class 'std::list<void *, Allocator<void *> >' requested here std::list< void *, Allocator< void * > > list; ^ In file included from test.cc:2: In file included from /usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/list:63: /usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/stl_list.h:450:40: error: no type named 'const_pointer' in 'Allocator<void *>' typedef typename _Tp_alloc_type::const_pointer const_pointer; ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~ /usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/stl_list.h:451:40: error: no type named 'reference' in 'Allocator<void *>' typedef typename _Tp_alloc_type::reference reference; ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~ /usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/stl_list.h:452:40: error: no type named 'const_reference' in 'Allocator<void *>' typedef typename _Tp_alloc_type::const_reference const_reference; ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~ 4 errors generated.
This is a bug in GCC's C++ standard library. When using a list, they are not properly wrapping access to the allocator through an allocator_traits. However, they do implement vector correctly. This code would compile if you used std::vector instead of std::list.