Visual Studio compiles this code fine, but gcc only lets it compile without the Template operator. With the Template operator it gives the following errors:
Line 29: error: expected `;' before "itrValue"
class Test
{
public:
Test& operator<<(const char* s) {return *this;} // not implemented yet
Test& operator<<(size_t s) {return *this;} // not implemented yet
Test& operator<< (const std::list<const char*>& strList)
{
*this << "count=" << strList.size() << "(";
for (std::list<const char*>::const_iterator itrValue = strList.begin();
itrValue != strList.end(); ++itrValue)
{
*this << " " << *itrValue;
}
*this << ")";
return *this;
}
template <class T>
Test& operator<< (const std::list<T>& listTemplate)
{
*this << "count=" << listTemplate.size() << "(";
// this is line 28, the next line is the offending line
for (std::list<T>::const_iterator itrValue = listTemplate.begin();
itrValue != listTemplate.end(); ++itrValue)
{
*this << " " << *itrValue;
}
*this << ")";
return *this;
}
};
GCC is right, const_iterator is a type, and template dependant in the template operator<<, you need to tell the compiler it's a type and not a variable:
typename std::list<T>::const_iterator
To complete #Pieter answer, which is correct, some more info on how templates are processed.
First of all, templates are only compiled whenever they are instantiated, so that if you do not instantiate the template for a given type then the code will never be compiled.
Now, when you do instantiate a template, there is a two steps validation of the template code. First the template is verified for correctness regardless of what the instantiation type is. To check with a simpler to understand example:
#include "a.h"
template <typename T> void f( T const & )
{
T::type x; // is T::type a type?
};
int main()
{
A a;
f( a );
}
During the first phase, the template is checked for syntax correctness without considering what A really is. At this time the syntax A::type could be a type by the name of 'type' or it could be a static variable by the same name.
struct A { // version 1
typedef int type;
};
struct A { // version 2
static std::string type;
};
std::string A::type = "A";
In the first case, type is indeed a type, in the second it is not. Now the standard states that if it is really a type then the programmer of the template must state so to inform the compiler with the syntax above:
template <typename T> void f( T const & a )
{
typename T::type x; // define a variable x of type T::type
}
Now, to complete the processing, the compiler must check that the template code is not only correct in itself, but that when it is instantiated with the particular type T it is also correct. This is what the compiler performs during the second stage of validation. It applies the type and rechecks for errors.
In your case, it is a little more controversial, as everyone (but the compiler) knows that std::list::const_iterator is a type for any given T. Well, it does not need to be. From a language standpoint, some code could provide a template specialization for a particular data type T that is different to the general list template. The compiler cannot know whether that could be so.
Note that it would be horribly wrong to specialize a template in the std namespace with something that changes behavior in as much as redefining the iterator types. But the compiler sees std namespace just as any other namespace, and list as any other templated class.
I think it's worth telling you about the other disambiguations. For typename i already answered another one here.
The other one is template. Look here:
template<typename T>
struct some {
template<int V>
struct other {
typedef int type;
static const int value = V;
};
};
template<typename V>
void doit() {
typename some<V>::template other<42>::type * int_pointer;
}
Note how we had to use both template and typename disambiguations. The typename told the compiler
The thing you access called ::type is indeed a type. Don't do multiplication, which would wrongly assume ::type is a static value (integer or something).
The template told the compiler
The other<42> is a template used with the 42 argument. It's not a comparison using operator> and operator< of other with 42 and what follows (which would indeed be total nonsense).
Related
I know it's generally a bad idea to rely on SFINAE unless absolutely necessary, but I'm curious about how to do the following anyway.
So let's say I have a function that prints a type to the console (class used for partial specialization since it more closely matches my situation):
template <class Ty>
class print
{
public:
print(Ty line)
{
std::cout << line << std::endl;
}
};
Since this is scaled down code, I'm not sure if it would also work with const types, but (because does not in my specific case) let's say the above function does not work with const types. Correct me if I'm wrong, but I believe this would be how you'd accomplish this with partial template specialization?
template <class Ty>
class print <const Ty>
{
public:
print(const Ty line)
{
std::cout << line << std::endl;
}
};
However, is there a way to use the <type_traits> header to do this? I've come across a question that was specific to char* and const char*, but it seems to be different when generalized. Additionally, that question (and answer) is nearly 7 years old.
I've tried the following code (untested) when trying to adapt the answer from the above question to my own situation, but it seems like there should simply be a better way to accomplish this task. In fact, I'm pretty sure my code won't compile (specifically if Ty is already const)
template <class Ty>
struct print_accept_const :
std::enable_if<std::is_same<Ty, Ty>::value || std::is_same<Ty, const Ty>>
{};
template <class Ty, class = print_accept_const<Ty>>
class print
{
print(Ty line)
{
std::cout << line << std::endl;
}
};
Just for reference, I'm using partial template specialization because I'm specializing this print class for std::vector objects, std::set objects, std::unordered_set objects, etc. If there is a way to do this without SFINAE, then I'd be totally open to that.
Edit 1
As asked in a comment, my exact error happens when I try to specialize for std::unordered_set objects.
template <class ValTy>
class print <std::unordered_set<ValTy>>
{
public:
print(std::unordered_set<int> lines) // 'int' instead of 'ValTy' to activate IntelliSense for errors
{
const auto last = --lines.end();
for (auto& line : lines)
{
// IntelliSense, for the line below when 'ValTy' is
// replaced with 'int', says:
//
// no instance of constructor "print<std::unordered_set<ValTy,
// std::hash<ValTy>, std::equal_to<ValTy>, std::allocator<ValTy>>>
// ::print(std::unordered_set<int, std::hash<int>, ...>)" matches
// the argument list. Argument types are (int).
//
print<ValTy> p(line);
}
}
}
Isn't clear what do you exactly want (enable when T is const or isn't const; if you have a function that print value of some types it's necessary wrap it in a template class? Can't you apply SFINAE directly over the function?) anyway... some useful elements...
(1) starting from C++11 there is std::is_const that you can use to check if a type is constant or not
(2) to make an example, a possible way to enable a specialization only for constant types is the following
template <typename T, typename = void>
struct print;
template <typename T>
struct print<T, typename std::enable_if<std::is_const<T>::value>::type>
{
print (T line)
{ std::cout << line << std::endl; }
};
The specialization can be simplified, starting from C++14, using std::enable_if_t
struct print<T, std::enable_if_t<std::is_const<T>::value>>
and, starting from C++17, also using std::is_const_v
struct print<T, std::enable_if_t<std::is_const_v<T>>>
(3) you can enable/disable directly the constructor, but only making is a template one (or SFINAE can't work)
template <typename T>
struct print
{
template <typename U = T,
typename std::enable_if<std::is_const<U>::value, int>::type = 0>
print (U line)
{ std::cout << line << std::endl; }
// possible alternative do-nothing constructor for not const values
template <typename U = T,
typename std::enable_if<! std::is_const<U>::value, int>::type = 0>
print (U)
{ }
};
Observe that, in this case, the SFINAE tests (std::is_same and std::is_const<U>) are (also) over the template parameter of the constructor, U, not over the template parameter of the class, T. Otherwise SFINAE doesn't works.
The first std::enable_if impose that T and U are the same.
Consider the following system:
template<typename T>
struct wrapper
{
operator T * () { return nullptr; }
};
template<typename Ret, typename T>
Ret func(T);
template<>
int func(float * in)
{
std::cout << "long";
}
template<>
long func(float * in)
{
std::cout << "int";
}
The purpose of the wrapper is to allow it to decay to the type it is templated to (it is a wrapper around a buffer of the type). Moreover, i have a set of functions that are templated specializations of a template. This is to circumvent the usual error when overloading based on only the return type.
This doesn't work though, as noted here:
// the following should work, but doesn't because it's instantiating
// the func<ret, wrapper<float>> which doesn't exist resulting in a linker error
// instead of selecting the int func(float *) overload
wrapper<float> w;
func<int>(w);
Conversely, i would like this to generate a compile-time error (but again, it's generating a link-time error):
// the following should generate a compile-time error
// since no explicit overload for int func(int *) exists
wrapper<int> w2;
func<int>(w2);
So ideally, i would like to disable the original template (maybe through sfinae if this is possible?) such that the overload resolution only considers the explicit specializations, and generates a compile-time error if no match is found. Can this be done?
A portable solution between clang and msvc is a must, but I'm using the newest versions of both.
Another approach may be to use static_assert:
template<typename Ret, typename T>
Ret func(T) {
static_assert(false, "template specialization required");
}
If you do
template<typename Ret> Ret func(float*);
it works as expected: Live example
While Jarod's answer solved one of the problems, i still needed a way to overload the function arguments (which in that case would generate 'no matching template' errors) - i probably didn't state that in the OP.
It dawned on me, that the parameter type(s) are always dependant on the return type. I could then construct a helper-struct, that would do the sfinae:
template<typename T>
struct option_of;
template<>
struct option_of<int>
{
typedef float value;
};
template<>
struct option_of<long>
{
typedef double value;
};
and then the default template would look like this:
template<typename Ret>
Ret func(typename const option_of<Ret>::value *);
and the overloads could then be constructed like this:
template<>
int func(const float * in)
{
std::cout << "long";
}
template<>
long func(const double * in)
{
std::cout << "int";
}
-without problems. Note that any other combination of returns and parameter types would be invalid (since they are not a specialization of the original template, which only considers the options i give it). This also reduces the only overload resolutions to the two overloads, and thus makes this possible:
wrapper<float> w;
func<int>(w); // works
func<long>(w); // invalid, because no combination of long and float exists according to option_of
wrapper<int> w2; // works, but
func<int>(w2); // invalid because option_of doesn't consider int's
The added bonus of course is the compiler recognizes the error at the call / instantiation with a correct error message, instead of some random static_assert / linker errors. Success!
Recently I came over an issue with clang++ 5.0.0 compiler where via ADL it was not picking up the correct function on Mac (but g++ did it correctly on Linux). I would like to know whether its a compiler issue OR poor class design in general.
Here is an example code (purely for illustration purpose):
namespace test {
class Ops {
public:
Ops():val_(0){}
template<typename T>
Ops& operator<< (const T& val) {
std::cout << "Called member function" << std::endl;
this->val_ = val;
return *this;
}
private:
int val_;
};
template<typename T>
struct Any {
T val_;
};
template <template<typename> class E, typename T>
Ops& operator<< (Ops& op, const E<T>& val) {
std::cout << "Global function" << std::endl;
return op;
}
}
int main() {
test::Ops op;
int k = 9;
test::Any<int> a;
op << a;
return 0;
}
I would like to know how ADL and template argument deduction wouldwork in step wise manner to find the best match ?
Would there be any situation for the same 'main body' the member function would be preferred in place of the free function ? (This is what is happening in the product build)
Thanks in advance.
This is what happens in detail and what every compiler should do: a candidate template function is found by qualified lookup
template <typename T>
test::Ops::operator<<(const T&)
while the second candidate is generated via ADL using template argument deduction (cfr. temp.deduct.conv)
template <template <typename> class E, typename T>
test::operator<<(test::Ops&, const E<T>&)
Afterwards overload resolution kicks in (cfr. 13.3.3) and the non-member one (F1) is preferred to the member (F2) one since
F1 and F2 are function template specializations, and the function template for F1 is more specialized
than the template for F2 according to the partial ordering rules described in 14.5.6.2.
and thus selected as the function to be called.
To answer your question: it depends on the overload resolution rules. Being a member function or in an inner scope doesn't affect the result and something like
namespace test {
class Ops {
public:
Ops():val_(0){}
template<typename T>
Ops& operator<< (const T& val) {
std::cout << "Called member function" << std::endl;
this->val_ = val;
return *this;
}
private:
int val_;
};
template<typename T>
struct Any {
T val_;
};
template <typename E>
Ops& operator<< (Ops& op, const E& val) {
std::cout << "Global function" << std::endl;
return op;
}
}
would just trigger an overload resolution error 'use of overloaded operator '<<' is ambiguous'.
As a plus: the member function is wrong even if it were chosen: this->val is assigned a non-integer type.
These two candidate functions are in the overload set:
// member function template, found by qualified lookup
template <typename T>
test::Ops::operator<<(const T&)
// non-member function template, found by ADL
template <template <typename> class E, typename T>
test::operator<<(test::Ops&, const E<T>&)
In operator lookup, no preference is given to members versus non-members. After template argument substitution, both function template specializations exactly match (with qualification conversions) the supplied argument types. But the function taking E<T> is more specialized than the one taking T, so the non-member function is chosen for this reason.
Apple clang 5.0.0 is based on LLVM clang 3.3svn. I can't find any version of LLVM clang which selects the member function. It could be a bug in Apple's code, but IMHO it's more likely to be some subtle difference in the code you are actually compiling or your environment. Have you tried compiling your example code with the suspect compiler?
I'm trying to build a templated C++ function that accepts, as its argument, a pointer to an object of an inner class. Here is a reduced version of the class structure involved, similar to a typical linked-list or tree class:
template <typename T>
struct Outer
{
struct Inner
{
T val;
Inner (T v) : val(v) { }
};
Inner* ptr;
Outer(T val)
{
ptr = new Inner(val);
}
};
I've made them structs to exclude any access control issues and removed some extraneous instance variables. With that class structure in mind, here are three functions, the first two of which aren't quite what I want:
template <typename T>
void testOuter (const Outer<T>& obj)
{
cout << obj.ptr->val << endl;
}
void testInnerInt (const Outer<int>::Inner* p)
{
cout << p->val << endl;
}
template <typename T>
void testInnerTemplated (const typename Outer<T>::Inner* p)
{
cout << p->val << endl;
}
This third function is basically what I want, header-wise (it's intended as a helper function in a larger body of code, of course), but it doesn't work. If I compile and run the following main function:
int main()
{
Outer<int> foo(5);
cout << foo.ptr->val << endl;
testInnerInt(foo.ptr);
//testInnerTemplated(foo.ptr);
testOuter(foo);
}
it runs just fine (printing 5 three times), but if I uncomment the line with the call to testInnerTemplated, I get a compiler error saying no matching function for call to ‘testInnerTemplated(Outer<int>::Inner*&)’ (in g++ 4.9.1). I guess it's a problem with the template lookup or matching, but how can I tell the compiler how to resolve it?
template <typename T>
void testInnerTemplated(const typename Outer<T>::Inner*);
The compiler can't deduce T through template argument deduction because this is a non-deduced context as defined in the standard:
The nondeduced contexts are:
The nested-name-specifier of a type that was specified using a qualified-id. A type that is a template-id in which one or more of the template-arguments is an expression that references a template-parameter.
When a type name is specified in a way that includes a nondeduced context, all of the types that comprise that type name are also nondeduced. However, a compound type can include both deduced and nondeduced types. [Example: If a type is specified as A<T>::B<T2>, both T and T2 are nondeduced. Likewise, if a type is specified as A<I+J>::X<T>, I, J, and T are nondeduced. If a type is specified as void f(typename A<T>::B, A<T>), the T in A<T>::B is nondeduced but the T in A<T> is deduced. ]
If you wish to recover the type information from Outer<> from within Inner, you can use traits.
template <typename T>
struct Outer
{
typedef T TypeParam;
struct Inner
{
typedef Outer<T> InnerOuter;
T val;
Inner (T v) : val(v) {}
};
Inner *ptr;
Outer (T val) : ptr(new Inner(val)) {}
};
Now define a more generic testInnerTemplated, but it uses traits to recover the type information passed to Outer<>.
template <typename T>
void testInnerTemplated (const T * p)
{
typename T::InnerOuter::TypeParam val = p->val;
std::cout << val << std::endl;
}
I have a template class that defines some member types. It's similar to how std::map defines it's value_type based on it's own template arguments, but in my case the type is more complex, so it's defined as nested class.
Now for debugging I would like to define operator<< for that type. But the compiler tells me it can't deduce the template parameters of the outer template.
My real code is not contrived like the following example, but this contrived example demonstrates the approach I tried and how it fails:
#include <iostream>
template <typename Value> class Outer;
template <typename Value>
std::ostream &operator<<(std::ostream &, const typename Outer<Value>::Inner &);
template <typename Value>
class Outer {
public:
struct Inner {
Value x;
};
void PrintSomething(Value v) {
// the real program does something useful with the inner class, of course
Inner inner = { v };
std::cout << "Inner = " << inner << std::endl; // <---- THIS SAYS IT CAN'T FIND operator<<
};
};
template <typename Value>
std::ostream &operator<<(std::ostream &s, const typename Outer<Value>::Inner &v) {
return s << v.x;
}
int main() {
Outer<int> o;
o.PrintSomething(42);
return 0;
}
This is complete sample to reproduce the problem. The compiler (I've tried 3 of them) says there is no overload of operator<< that would take second argument of type Outer<int>::Inner. When I try the same thing with different function that does not have other overloads, it instead says C2783: could not deduce template argument for 'identifier', gcc and clang keep saying there is no overload that takes second argument Outer<int>::Inner).
So is there a way to define operator<< taking Outer<Value>::Inner for any Value as it's right (so it can't be defined as member) argument?
Note: I need it to compile in several compilers and some of them don't have any C++11 features, so I need it to be C++03.
What you have there is a so-called non-deducible context. How could Value ever be deduced? You can partially specialize class templates, making it practically impossible for the compiler to even try and test every possible instantiation (of which there are.. well, infinite).
There are two workarounds: Take Inner out of Outer, or make operator<< an inline friend. The latter is the usual way people go.
template<class T>
struct Outer{
struct Inner{
T value;
friend std::ostream& operator<<(std::ostream& os, Inner const& v){
return os << v.value:
}
};
// ...
};