Hey,
I am trying to get the following code to compile and I am not sure
wether this is my mistake or a compiler bug:
--------------------------------- test.cpp
template <class T, void (T::*foo)() > class X { };
template <class T>
auto type_constructor( void (T::*f)() ) -> X< T, f >;
class Y
{
public:
void bar() {};
};
int main () {
decltype( type_constructor( &Y::bar ) ) x;
}
The declaration of the template type_constructor is broken. Think
about it this way: type_constructor has one template parameter, so
type_constructor<Y> should refer to a single function; however, you're
trying to specify it as returning multiple types.
-Eli
Or put another way, the second template argument for X, "foo", should be a constant function pointer, but the parameter to type_constructor, "f", is not.
- John
Could the diagnostics be improved over
test.cpp:4:6: note: candidate template ignored: substitution failure
[with T = Y]
auto type_constructor( void (T::*f)() ) -> X< T, f >;
^
?
Maybe an added note that points at the f in X<T,f> to say that that's why the substitution failed?
Here's an example of a similar mistake:
#include <functional>
template<typename T>
void get(T const &t,size_t N) {
std::get<N>(t);
}
int main () {
get(std::make_tuple(1,'a',1.2),2);
}
When compiling this the diagnostics include several notes like the following
/usr/include/c++/v1/__tuple:104:1: note: candidate template ignored: invalid explicitly-specified
argument for template parameter '_Ip'
get(array<_Tp, _Size>&) _NOEXCEPT;
"invalid explicitly-specified argument for template parameter" is a little better but it'd be nice to see something pointing directly at the 'N' in std::get<N>(t) saying it's not legal to use arguments as template parameters. Would this be hard to add? Maybe I can give it a try.
Could the diagnostics be improved over
test.cpp:4:6: note: candidate template ignored: substitution failure
[with T = Y]
auto type_constructor( void (T::*f)() ) -> X< T, f >;
^
?
Maybe an added note that points at the f in X<T,f> to say that that's why the substitution failed?
While I agree that 'substitution failure' by itself is not very helpful, I'm very reluctant to use multiple notes per failed overload candidate, at least for the default console diagnostics. Is there a good way to explain the problem based on the kind of substitution failure?
Here's an example of a similar mistake:
#include <functional>
template<typename T>
void get(T const &t,size_t N) {
std::get<N>(t);
}
int main () {
get(std::make_tuple(1,'a',1.2),2);
}
When compiling this the diagnostics include several notes like the following
/usr/include/c++/v1/__tuple:104:1: note: candidate template ignored: invalid explicitly-specified
argument for template parameter '_Ip'
get(array<_Tp, _Size>&) _NOEXCEPT;
"invalid explicitly-specified argument for template parameter" is a little better but it'd be nice to see something pointing directly at the 'N' in std::get<N>(t) saying it's not legal to use arguments as template parameters. Would this be hard to add? Maybe I can give it a try.
Again, we'd rather not introduce extra notes, but it would be fine to just specialize this note for common problems. For example, here you could say:
note: candidate template ignored: explicit argument for template parameter '_lp' is not a type
or maybe even
note: candidate template ignored: explicit argument 'N' for template parameter '_lp' is not a type
where N is a string derived from pretty-printing the argument expression.
John.
Could the diagnostics be improved over
test.cpp:4:6: note: candidate template ignored: substitution failure
[with T = Y]
auto type_constructor( void (T::*f)() ) -> X< T, f >;
^
?
Maybe an added note that points at the f in X<T,f> to say that that's why the substitution failed?
While I agree that 'substitution failure' by itself is not very helpful, I'm very reluctant to use multiple notes per failed overload candidate, at least for the default console diagnostics. Is there a good way to explain the problem based on the kind of substitution failure?
Okay, I think not multiplying notes that way is good. Thinking about it more, it seems like this shouldn't even be a note attached to an error because I don't think there's any way the template could ever be instantiated. Instead as soon as clang sees:
template <class T>
auto type_constructor( void (T::*f)() ) -> X< T, f >;
it seems like it should pop out an error declaring that the template is invalid (and explaining why by stating that the function's parameter 'f' can't be used as a non-type template parameter in X<T,f>). I'm not exactly sure what the restrictions are on what values can be used as non-type template parameters, but it's obvious that the value has to be available at compile time.
So later on, when the code tries to use this template the note can say something like this:
test.cpp:4:6: note: candidate template ignored: invalid template
template<typename T> auto type_constructor( void (T::*f)() ) -> X< T, f >;
Here's an example of a similar mistake:
#include <functional>
template<typename T>
void get(T const &t,size_t N) {
std::get<N>(t);
}
int main () {
get(std::make_tuple(1,'a',1.2),2);
}
When compiling this the diagnostics include several notes like the following
/usr/include/c++/v1/__tuple:104:1: note: candidate template ignored: invalid explicitly-specified
argument for template parameter '_Ip'
get(array<_Tp, _Size>&) _NOEXCEPT;
"invalid explicitly-specified argument for template parameter" is a little better but it'd be nice to see something pointing directly at the 'N' in std::get<N>(t) saying it's not legal to use arguments as template parameters. Would this be hard to add? Maybe I can give it a try.
Again, we'd rather not introduce extra notes, but it would be fine to just specialize this note for common problems. For example, here you could say:
note: candidate template ignored: explicit argument for template parameter '_lp' is not a type
or maybe even
note: candidate template ignored: explicit argument 'N' for template parameter '_lp' is not a type
where N is a string derived from pretty-printing the argument expression.
John.
Similarly, instead of attaching extra notes to the error clang should be able to recognize that this case is an invalid use of a non-type template parameter. This way there wouldn't even be a reason to look at any candidate templates and all of the (possibly many) notes about failed candidate templates can be eliminated. All the developer needs to know is that you can't pass runtime values to template parameters, and clang can point him directly at the spot where he's trying to do that.
This is certainly something that Clang could detect by looking at the form of the declaration. The compiler is allowed (but not required) to reject this template (since there are no valid instantiations of the template).
As for the more general case... it would be great to give more information about why a particular candidate failed during substitution, perhaps by trapping the diagnostic generated while performing the substitution and adding its text at the end of the "substitution failure" note. We certainly can't have multiple notes, though.
- Doug