Skip to content

GitLab

  • Menu
Projects Groups Snippets
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
  • hyteg hyteg
  • Project information
    • Project information
    • Activity
    • Labels
    • Planning hierarchy
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 36
    • Issues 36
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 3
    • Merge requests 3
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • hyteg
  • hyteghyteg
  • Issues
  • #175

Closed
Open
Created Feb 23, 2022 by Marcus Mohr@mohrDeveloper

BlockOperator, Template Instantiation and Microsoft Compiler

Hi,

as encouraged in our last developer meeting I will try to document the issue we had recently discussed in the chat. There had been a problem report on compiling on Windows with the Microsoft Visual Studio compiler. This resulted in template instantiation errors of the following form, here as an example for the BlockOperatorBasicTest

[build] C:\Users\[removed]\dev\hyteg\src\hyteg/functions/FunctionWrapper.hpp(179,1): error C2660: 'hyteg::BlockFunction<value_t>::enumerate': function does not take 2 arguments [C:\Users\[removed]\dev\hyteg\build\tests\hyteg\BlockOperatorBasicTest.vcxproj]
[build]           with
[build]           [
[build]               value_t=walberla::real_t
[build]           ]
[build] C:\Users\[removed]\dev\hyteg\src\hyteg/functions/BlockFunction.hpp(264,9): message : see declaration of 'hyteg::BlockFunction<value_t>::enumerate' [C:\Users\[removed]\dev\hyteg\build\tests\hyteg\BlockOperatorBasicTest.vcxproj]
[build]           with
[build]           [
[build]               value_t=walberla::real_t
[build]           ]
[build] C:\Users\[removed]\dev\hyteg\src\hyteg/functions/FunctionWrapper.hpp(179): message : while compiling class template member function 'void hyteg::FunctionWrapper<func_t>::enumerate(walberla::uint_t,double &) const' [C:\Users\[removed]\dev\hyteg\build\tests\hyteg\BlockOperatorBasicTest.vcxproj]
[build]           with
[build]           [
[build]               func_t=thType
[build]           ]
[build] C:\Users\[removed]\dev\hyteg\src\hyteg/functions/GenericFunction.hpp(58): message : see reference to class template instantiation 'hyteg::FunctionWrapper<func_t>' being compiled [C:\Users\[removed]\dev\hyteg\build\tests\hyteg\BlockOperatorBasicTest.vcxproj]
[build]           with
[build]           [
[build]               func_t=thType
[build]           ]
[build] C:\Users\[removed]\dev\hyteg\src\hyteg/operators/BlockOperator.hpp(158): message : see reference to function template instantiation 'const func_t &hyteg::GenericFunction<value_t>::unwrap<srcBlockFunc_t>(void) const' being compiled [C:\Users\[removed]\dev\hyteg\build\tests\hyteg\BlockOperatorBasicTest.vcxproj]
[build]           with
[build]           [
[build]               func_t=thType,
[build]               value_t=double,
[build]               srcBlockFunc_t=thType
[build]           ]
[build] C:\Users\[removed]\dev\hyteg\src\hyteg/operators/BlockOperator.hpp(158): message : see reference to function template instantiation 'const func_t &hyteg::GenericFunction<value_t>::unwrap<srcBlockFunc_t>(void) const' being compiled [C:\Users\[removed]\dev\hyteg\build\tests\hyteg\BlockOperatorBasicTest.vcxproj]
[build]           with
[build]           [
[build]               func_t=thType,
[build]               value_t=double,
[build]               srcBlockFunc_t=thType
[build]           ]
[build] C:\Users\[removed]\dev\hyteg\src\hyteg/operators/BlockOperator.hpp(156): message : while compiling class template member function 'void hyteg::BlockOperator<thType,thType>::smooth_gs(const hyteg::GenericFunction<value_t> &,const hyteg::GenericFunction<value_t> &,size_t,hyteg::DoFType) const' [C:\Users\[removed]\dev\hyteg\build\tests\hyteg\BlockOperatorBasicTest.vcxproj]
[build]           with
[build]           [
[build]               value_t=double
[build]           ]
[build] C:\Users\[removed]\dev\hyteg\tests\hyteg\operators\BlockOperatorBasicTest.cpp(76): message : see reference to class template instantiation 'hyteg::BlockOperator<thType,thType>' being compiled [C:\Users\[removed]\dev\hyteg\build\tests\hyteg\BlockOperatorBasicTest.vcxproj]
[build] Build finished with exit code 1

The compiler is of course correct in the following respect. The BlockFunction does not provide a version of enumerate that accepts an offset parameter, as the other functions do. However, the BlockFunction was also not intended to be wrapped inside a FunctionWrapper object. So the interesting question here is: Why does the Microsoft compiler see the need to instantiate FunctionWrapper< thType >, where thType = P2P1TaylorHoodBlockFunction< real_t > is a child of BlockFunction<real_t>, while neither GCC, nor Clang, nor the Intel compiler does?

My current working hypothesis is the following:

  • BlockOperator< srcBlockFunc_t, dstBlockFunc_t> inherits from GSSmoothable< GenericFunction< typename srcBlockFunc_t::valueType >.

  • As GSSmoothable::smooth_gs() is pure virtual, it needs to be implemented by BlockOperator and must be instantiable for the given template arguments, when one attempts to generate an object of type BlockOperator. In the above case srcBlockFunc_t = thType = P2P1TaylorHoodBlockFunction< real_t > which is a child of BlockFunction<real_t>.

  • BlockOperator::smooth_gs( GenericFunction, ...) contains the two lines:

    const auto& dst_unwrapped = dst.template unwrap< srcBlockFunc_t >();
    const auto& rhs_unwrapped = rhs.template unwrap< dstBlockFunc_t >();

    which invoke the templated member function GenericFunction::unwrap(). This in turn does the following:

    template < typename func_t >
    func_t& unwrap()
    {
      auto realMe = static_cast< FunctionWrapper< func_t >* >( this );
      return realMe->unwrap();
    };
  • It seems that the static cast is the reason why the compiler attempts to instantiate FunctionWrapper< thType > and finally looks for the missing BlockFunction< real_t >::enumerate() version. However, two questions remain:

    1. As no object of type FunctionWrapper< srcBlockFunc_t > is requested, but we only have a cast to pointer, why can the template instance not remain abstract? Is that what the other compilers do?
    2. The instantiations involved seem implicit and, thus, should be lazy. But there is no direct call to FunctionWrapper<srcBlockFunc_t>::enumerate().

The complexity here is high and I have no direct access to the compiler to experiment, so the analysis might by faulty. However, commenting out the inheritance and the smooth_gs() methods in BlockOperator fixed the problem for the Microsoft compiler. So at least no falsification.

Cheers
Marcus

Assignee
Assign to
Time tracking