2021-03-21

21: "no arguments to ~ that depend on a template parameter, so a declaration of ~ must be available" C++ Error?

<The previous article in this series | The table of contents of this series | The next article in this series>

The error is probably because of "two-stage name lookup", which seems unwise to have been introduced, but has to be learned anyway.

Topics


About: C++

The table of contents of this article


Starting Context



Target Context


  • The reader will know the mechanism of "two-stage name lookup" and how to solve a "there are no arguments to ~ that depend on a template parameter, so a declaration of ~ must be available [-fpermissive]" error.

Orientation


There are some articles that discuss some other unwise C++ decisions, like this about templates, this about 'const', and this about class static fields.


Main Body

Stage Direction
Hypothesizer 7 soliloquies.


1: Meeting a "there are no arguments to ~ that depend on a template parameter, so a declaration of ~ must be available" Compile Error


Hypothesizer 7
"there are no arguments to ‘methodC0’ that depend on a template parameter, so a declaration of ‘methodC0’ must be available"?

Huh?

My code is this.

'theBiasPlanet/tests/templatesTest1/ClassC.hpp'

@C++ Source Code
#ifndef __theBiasPlanet_tests_templatesTest1_ClassC_hpp__
#define __theBiasPlanet_tests_templatesTest1_ClassC_hpp__

namespace theBiasPlanet {
	namespace tests {
		namespace templatesTest1 {
			template <typename T> class ClassC {
				public:
		   			 int methodC0 (int a_argument0);
				};
		}
	}
}

#endif

'theBiasPlanet/tests/templatesTest1/ClassC.tpp'

@C++ Source Code
#include "theBiasPlanet/tests/templatesTest1/ClassC.hpp"

namespace theBiasPlanet {
	namespace tests {
		namespace templatesTest1 {
			template <typename T> int ClassC <T>::methodC0 (int a_argument0) {
       		 	return a_argument0;
			}
		}
	}
}

'theBiasPlanet/tests/templatesTest1/ClassD.hpp'

@C++ Source Code
#ifndef __theBiasPlanet_tests_templatesTest1_ClassD_hpp__
#define __theBiasPlanet_tests_templatesTest1_ClassD_hpp__

#include "theBiasPlanet/tests/templatesTest1/ClassC.hpp"

namespace theBiasPlanet {
	namespace tests {
		namespace templatesTest1 {
			template <typename T> class ClassD : public ClassC <T> {
				public:
					int methodD0 (int a_argument0);
			};
		}
	}
}

#endif

'theBiasPlanet/tests/templatesTest1/ClassD.tpp'

@C++ Source Code
#include "theBiasPlanet/tests/templatesTest1/ClassD.hpp"

namespace theBiasPlanet {
	namespace tests {
		namespace templatesTest1 {
			template <typename T> int ClassD <T>::methodD0 (int a_argument0) {
				return methodC0 (a_argument0);
			}
		}
	}
}

Additions to 'theBiasPlanet/tests/templatesTest1/TemplatesInstantiator.cpp'

@C++ Source Code
#include "theBiasPlanet/tests/templatesTest1/ClassD.tpp"

template class ClassD <int>;

The error is flagging the "return methodC0 (a_argument0);" line in 'ClassD.tpp'.

If there is someone who suspects that the error message is foolish, I would like to assure him or her that it certainly is.

First, whether "there are no arguments to ‘methodC0’ that depend on a template parameter" or not, "a declaration of ‘methodC0’" has to be available, does it not? . . . The message is as though a function template call that has a template-parameter-dependent argument requires no declaration, which is totally against my understanding on C++.

Second, the message's focusing on "arguments" is beside the point. . . . As the function template has no argument at all, of course, it has no argument that depends on any template; so what? Do I have to add a dummy argument or something? Foolish!

Third, I cannot help but think that the declaration is indeed available, as it is in 'ClassC.hpp' and is included via 'ClassD.hpp'. . . . Well, I now know that according to the unwise "two-stage name lookup", the declaration is not recognized as to be available, but what an unhelpful message!


2: I Just Have Been Forced to Meet a Case of "two-stage name lookup"


Hypothesizer 7
In fact, the C++ committee was hit by a bad idea: "two-stage name lookup".

Well, that bad idea is being explained badly here.

A bad thing about the document is that it does not clearly state the specifications in the indispensable 2 aspects: 1) which names are to be resolved at the 1st stage and 2) which entities are eligible to be resolved to (be pointed to by the names) at the 1st stage.

In fact, until it comes to "This distinction between lookup of dependent and non-dependent names is called two-stage (or dependent) name look up", it explains only the 1st aspect: being "dependent" is the criterion for the name to be not resolved at the 1st stage, nothing else.

But it suddenly declares "It will not look into the base class, since that is dependent". . . . Huh? I did not know that any dependent class was not looked into in the 2nd aspect. . . .

Well, the rules in the 1st aspect and the rules in the 2nd aspect look unprincipled.

In the 1st aspect, that "i" in "return i;" seems to be regarded to be not "dependent" although it is inside the parameterized 'struct' template, which is really objectionable to me: I deem that the inside of any parameterized block is wholly a dependent context. . . . That is the major banana skin on the mechanism. . . . In my common sense, that "i" is nothing but "this->i" or "Derived <T>::i", without being expressed explicitly so: as I always avoid using global variables, I do not expect any global variable there, so what else can it be?

Anyway, on the other hand, in the 2nd aspect, "i" in "int i;" is not eligible to be resolved to, because it is inside the parameterized 'struct' template? . . . Why did being inside a parameterized block begin to matter, only for the 2nd aspect? . . . The document states "you may declare specializations of Base even after declaring Derived", but so what? . . . Supposing that I declare 'Base <int>', 'Base <double>', 'Base <::std:string>', or whatever after declaring 'Derived', I do not see why "so the compiler cannot really know what i would refer to", because the compiler can just resolve "i" in 'Derived <T>' to that "i" in 'Base <T>' in my opinion. . . . I do not see what the document is worried about.

The promoters of the mechanism seems to have been assailed by the idea that a name's being resolved at an so-called "instantiation" (I oppose to that usage of the term) of a template is a problem, but I do not see any problem there: it is nothing but quite natural that the name is resolved at the time.

As the mechanism seems to be concerned with resolutions of global entities, I wonder why global entities are being given such preference; for me, global entities are pariahs to be avoided, and because of such preference to those pariahs, decent acts like base class member accesses are being bothered.


3: A Solution


Hypothesizer 7
The mechanism is unwise, but I have to make the project compile.

How? Well, although the error message misleadingly tells about "arguments", that is not any issue at all; the issue is that the 'methodC0' call is regarded to be not dependent and is decided to be a global function.

So, I have to make the 'methodC0' call "dependent", like 'this->methodC0 ()'.

. . . A foolish rule, I say.


References


<The previous article in this series | The table of contents of this series | The next article in this series>