Skip to content

Template is treated as operator< #360

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
kokosxD opened this issue Oct 9, 2020 · 2 comments
Closed

Template is treated as operator< #360

kokosxD opened this issue Oct 9, 2020 · 2 comments
Labels
conclusion: invalid Issue/PR not valid type: imperfection Perceived defect in any part of project

Comments

@kokosxD
Copy link

kokosxD commented Oct 9, 2020

When an function from template class SecondClass calls a template function which takes a function as it template argument from template class FirstClass, the Arduino IDE treats the <> as the operator<. Note that this is happening ONLY with template classes. If I remove the templates from the classes without removing the templates from their member functions, it compiles fine.

Apart from the Arduino-specific code, it compiles without any errors or warnings in Visual Studio 2019.

How to reproduce

// Returns the length of the given string
template<typename _Ty1>
const unsigned int len(const _Ty1* const _str) noexcept{
	for(unsigned int length = 0; ; length++){
		if(! _str[length]){
			return length;
		}
	}
}

// Comparison function
template<typename _Ty1>
inline const bool CaseSensitive(const _Ty1& _ch1, const _Ty1& _ch2) noexcept{
	return _ch1 == _ch2;
}

// Template type of comparison function
template<typename _Ty1>
using CompFunc = const bool(*)(const _Ty1&, const _Ty1&) noexcept;

template<typename _Ty1>
class FirstClass final{
public:

	// Takes a function as its template argument and 2 characters to compare
	template<CompFunc<_Ty1> _comp>
	inline const bool FirstAreSame(const _Ty1& _ch1, const _Ty1& _ch2) const noexcept{
		return _comp(_ch1, _ch2);
	}
};

template<typename _Ty1>
class SecondClass final{
public:
	const bool SecondAreSame(const FirstClass<_Ty1>& _first_object, const _Ty1* const _str1, const _Ty1* const _str2) const noexcept{
		const unsigned int str1_len = len<_Ty1>(_str1);
		const unsigned int str2_len = len<_Ty1>(_str2);

		if(str1_len != str2_len){
			return false;
		}

		for(unsigned int character = 0; character < str1_len; character++){

			// It calls FirstClass<_Ty1>::FirstAreSame<>
			if(! (_first_object.FirstAreSame<CaseSensitive>(_str1[character], _str2[character]))){
				return false;
			}
		}

		return true;
	}
};

void setup(){}

void loop(){
	const FirstClass<char> first_object = FirstClass<char>();
	const SecondClass<char> second_object = SecondClass<char>();
	const char* const str1 = "this is a test";
	const char* const str2 = "this is a test";
	if(second_object.SecondAreSame(first_object, str1, str2)){
		Serial.write("Strings are same!");
	}
	else{
		Serial.write("Strings are NOT same!");
	}

	exit(0);
}

Error message

C:\Users\username\Arduino Project\Arduino.ino: In instantiation of 'const bool SecondClass<_Ty1>::SecondAreSame(const FirstClass<_Ty1>&, const _Ty1*, const _Ty1*) const [with _Ty1 = char]':
C:\Users\username\Arduino Project\Arduino.ino:63:57:   required from here
Arduino:47:36: error: invalid operands of types '<unresolved overloaded function type>' and '<unresolved overloaded function type>' to binary 'operator<'
    if(! (_first_object.FirstAreSame<CaseSensitive>(_str1[character], _str2[character]))){
          ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
exit status 1
invalid operands of types '<unresolved overloaded function type>' and '<unresolved overloaded function type>' to binary 'operator<'

What I'm using

  • Arduino IDE 1.8.13
  • Arduino Uno 3
  • Windows 10 64-bit
@matthijskooijman
Copy link
Collaborator

This is not an Arduino-specific problem, I think you're code is incorrect. Running this against normal g++ produces the same error. Using clang provides a hint about the problem:

matthijs@grubby:~$ clang-10 -c testfoo.cpp 
testfoo.cpp:19:58: error: exception specifications are not allowed in type aliases
using CompFunc = const bool(*)(const _Ty1&, const _Ty1&) noexcept;
                                                         ^
testfoo.cpp:46:24: error: missing 'template' keyword prior to dependent template name 'FirstAreSame'
   if(! (_first_object.FirstAreSame<CaseSensitive>(_str1[character], _str2[character]))){
                       ^
testfoo.cpp:62:19: note: in instantiation of member function 'SecondClass<char>::SecondAreSame' requested here
 if(second_object.SecondAreSame(first_object, str1, str2)){
                  ^

(Here, testfoo.cpp. is your code minus the references to Serial and exit)

So apparently you need to explicitly state to the compiler that FirstAreSame is a template using the template keyword. I'm not sure off-hand what the exact rules are here, but I think you can figure it out from here.

Anyway, not an Arduino bug, so I'm closing this.

@kokosxD
Copy link
Author

kokosxD commented Oct 9, 2020

So apparently you need to explicitly state to the compiler that FirstAreSame is a template using the template keyword.

I added the template keyword before the function name and it worked!

// It calls FirstClass<_Ty1>::FirstAreSame<>
if(! (_first_object.template FirstAreSame<CaseSensitive>(_str1[character], _str2[character]))){
	return false;
}

Also, I forgot to initialize Serial, so first I didn't get any output. Thank you so much!

@per1234 per1234 added the type: imperfection Perceived defect in any part of project label Sep 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
conclusion: invalid Issue/PR not valid type: imperfection Perceived defect in any part of project
Projects
None yet
Development

No branches or pull requests

3 participants