Re: Incorrect stream operator called for a template class
On 2013-04-18 22:49, Ryan wrote:
On Thursday, April 18, 2013 7:00:02 AM UTC-7, SG wrote:
The compiler will see your operator<< but the problem is that it won't
try to figure out what T is because none of your function's parameter
types are "deducible contexts" with respect to T. At the op<< call
site you have a stream on the left hand side and an int on the right
hand side. Should the compiler now try every possible T to see whether
B<T>::foo is an int? What if there are many such Ts like in your case?
B<int>::foo is an int as well as B<double>::foo is an int.
So what do I need to do to get a "deducible context"?
It depends what you want to realize. If I understand your code pattern
correctly, I don't see any way of deducing the type of T here from the
type of the member B<T>::m_Bs: The type of B<T>::m_Bs is some unique
type Bs' derived from A::As, but this is not sufficient information to
deduce the template Parameter T of the *nesting* type B<T>, because it
is not the template form of B<T> that makes the concrete nested type
unique from other nested types such as
class K {
public:
struct Bs : public A::As {} m_Bs;
};
Assume you have
int main()
{
K k;
std::cout << k.m_Bs << std::endl;
}
How should the compiler "know" that the provided argument value that has
type K::Bs is in a different sense some unique derived type compared to
some instance of B<X>::m_Bs.
In my code
the T types being passed to B are classes that have their own op<<
that I want to call.
I don't understand what you mean by "the T types being passed to B",
because you never assign anything to B. Nor do I understand what you are
trying to realize here, because your overload
template <typename T>
std::ostream & operator<<(std::ostream & stream, typename B<T>::Bs
const& value);
ignores any aspects of the template parameter T of the B template.
If you want to discriminate "class types named Bs that are contained in
a B template from other derived classes of A::As", you have to make this
special uniqueness testable. Here is a simple sketch to demonstrate how
this can be done:
#include <type_traits>
struct B_tag{};
template <typename T>
class B : public A {
public:
struct Bs : A::As, B_tag {} m_Bs;
};
template<class T>
struct has_B_marker
{
// Add further constraints here:
static const bool value = std::is_base_of<B_tag, T>::value &&
std::is_base_of<A::As, T>::value;
};
template <typename T>
typename std::enable_if<has_B_marker<T>::value, std::ostream&>::type
operator<<(std::ostream& stream, const T& value) {
stream << static_cast<A::As>(value) << std::endl;
stream << "Class Bs" << std::endl;
return stream;
}
If you also need to deduce the actual template parameter type T, you can
extend the approach to use a template marker such as in the following
example:
#include <type_traits>
#include <typeinfo>
template<class T>
struct Bs : A::As {};
template <typename T>
class B : public A {
public:
typedef ::Bs<T> Bs;
Bs m_Bs;
};
template<class T>
struct is_Bs_impl
{
static const bool value = false;
typedef void param_type;
};
template<class T>
struct is_Bs_impl<Bs<T>>
{
static const bool value = true;
typedef T param_type;
};
template<class T>
struct is_Bs
{
private:
typedef is_Bs_impl<
typename std::remove_cv<typename std::remove_reference<T>::type>::type
> impl_type;
public:
static const bool value = impl_type::value;
typedef typename impl_type::param_type param_type;
};
template<class T>
struct is_marked_Bs
{
// Add further constraints here:
static const bool value = is_Bs<T>::value &&
std::is_base_of<A::As, T>::value;
};
template <typename T>
typename std::enable_if<is_marked_Bs<T>::value, std::ostream&>::type
operator<<(std::ostream& stream, const T& value) {
stream << static_cast<A::As>(value) << std::endl;
stream << "Class Bs<T>" << std::endl;
stream << "T: " << typeid(typename is_Bs<T>::param_type).name() <<
std::endl;
return stream;
}
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]