0

With the below code:

materia.h:

#ifndef MATERIA_H
#define MATERIA_H

class material
{
public:
  template <class type>
  static material* MakeMaterial(typename type::configtype, long);
  template <class type>
  void CreateNaturalForm(typename type::configtype, long);
  … 
};

template <class type>
material* material::MakeMaterial(typename type::configtype Config, long Volume)
{
  return type::Spawn(Config, Volume);
}

#endif

materias.h:

#ifndef MATERIAS_H
#define MATERIAS_H

#include "materia.h"
#include "confdef.h"

class solid : public material {
public:
  typedef solidmaterial configtype;
  … 
};

template material* material::MakeMaterial<solid>(solidmaterial, long);

template <class type>
void material::CreateNaturalForm(typename type::configtype Config, long Volume)
{
  … 
  MakeMaterial(Config, Volume); // Error here
  … 
}

template void material::CreateNaturalForm<solid>(solidmaterial, long);

#endif

confdef.h:

#ifndef CONFDEF_H
#define CONFDEF_H

enum solidmaterial {
  WOOD,
  … 
};

#endif

main.cpp

#include "materia.h"
#include "materias.h"
#include "confdef.h"

int main()
{
  material::MakeMaterial(WOOD, 500); // Same error here
}

(Here's an online version of the above code that reproduces the error.)

I get the following compilation error message on the commented line:

No matching function for call to 'MakeMaterial'

What am I doing wrong? Shouldn't the explicit instantiation allow the compiler to see the correct function?

The code compiles if I write MakeMaterial<solid> explicitly, but the whole point here is to deduce type from the Config argument. How can I achieve this?

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • Please make it compile, first (Read and understand the error message, or ask what an error message means). –  Jun 29 '15 at 18:33
  • That should not be the first one (or you might have ignored a warning) –  Jun 29 '15 at 18:36
  • @DieterLücking "Candidate template ignored: couldn't infer template argument 'type'" – Emil Laine Jun 29 '15 at 18:38
  • 1
    Just replace two `template` by `template<>``for specialization –  Jun 29 '15 at 18:44
  • What is the purpose of the first function argument to `MakeMaterial`? Is an instance of something really required, or is just the type needed? – Cheers and hth. - Alf Jun 29 '15 at 18:45
  • @Cheersandhth.-Alf The enum value itself is required. The enum _type_ defines which `material` subclass to use. – Emil Laine Jun 29 '15 at 18:46
  • Would it help then to just use `solidmaterial` (the enum type) as type for the argument, and ditch the templating? – Cheers and hth. - Alf Jun 29 '15 at 18:48
  • Shouldn't g++ emit an diagnostic message omitting the '<>' in a specialization? –  Jun 29 '15 at 18:51
  • @DieterLücking Those are instantiations, not specializations. A specialization is not good here because the body is always simply `return type::Spawn(Config, Volume);`, only the template parameter changes. – Emil Laine Jun 29 '15 at 18:53
  • The first error should be `error: ‘MakeMaterial’ was not declared in this scope``(it's a static function of `class material` –  Jun 29 '15 at 19:04
  • @DieterLücking True, thanks, I typoed. – Emil Laine Jun 29 '15 at 19:07

1 Answers1

2

In the call

MakeMaterial(Config, Volume); // Error here

the compiler is asked to find a match where type::configtype in the function template, is the type of Config.

But nothing tells the compiler what to match type to: this is not an explicit instantiation.

In general there could be hundreds of types that type could be matched to, where type::configtype would be the type of Config. C++ does not support the special case where there is only one such possible type.

How to fix that depends on what you meant to accomplish.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • I'm trying to make the compiler deduce `type` from the type of `Config`. With the explicit instantiation I'm telling that if `Config` is of type `solidmaterial` then `type` is `solid`. Shouldn't what I'm calling in `main` be completely unambiguous? – Emil Laine Jun 29 '15 at 18:41
  • @zenith: OK, you're *trying* say that. But the compiler only sees that this is one possibility. You could define an arbitrary number of other possibilities that would have the same `T::configtype`. – Cheers and hth. - Alf Jun 29 '15 at 18:43