5 Replies - 7803 Views - Last Post: 14 June 2012 - 01:25 PM

#1 ishkabible  Icon User is offline

  • spelling expret
  • member icon




Reputation: 1622
  • View blog
  • Posts: 5,709
  • Joined: 03-August 09

decltype expression can't use member from publicly inherited base

Posted 11 June 2012 - 08:48 PM

so, I'm working on a parser that uses templates with function types in a very generic way and so to determine the return type I figured I'd use decltype sense so long as the code I would be using at runtime would compile it *should* be able to tell me the type but I ran into a snag(there is an easy practical solution but I can't see why my first idea shouldn't work)

template<
	class Value,
	class Action = void
>
struct result : public result<Value, void> {
	Action action;
	//here, why can't I do this?
	typedef decltype(action(val)) value_type;
};

template<class Value>
struct result<Value, void> {
	typedef Value value_type;
	bool good;
	Value val;
	operator bool() const {
		return good;
	}
};


so I get an error(below) saying that 'val' is not in scope even though result<X,Y> publicly inherits result<X,void> which and 'val' is a public member. I looked though the n3242(a close draft of the C++11 standard) and couldn't find anything that said this isn't possible(nor anything that said it was). doesn't mean it's not there just means I couldn't find it.

so why can't this be done? is it an error in GCC or lack of C++11 support? is there something in the standard that says this can't be done(and if so why)?

edit:
you can use result<int, int(*)(int)>

This post has been edited by ishkabible: 11 June 2012 - 08:52 PM


Is This A Good Question/Topic? 0
  • +

Replies To: decltype expression can't use member from publicly inherited base

#2 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2089
  • View blog
  • Posts: 3,181
  • Joined: 21-June 11

Re: decltype expression can't use member from publicly inherited base

Posted 12 June 2012 - 12:17 AM

The problem isn't specific to your usage of decltype. The problem is that because of C++'s lookup rules regarding templates, you can't use inherited members unqualified in templates. So if you tried to use val anywhere in your subclass (e.g. inside a member function), you'd get the same error.

The usual way to solve this would be to use this->val instead of val. However that doesn't work with decltype. What does work however is decltype(action(result<Value,Action>::val)).
Was This Post Helpful? 1
  • +
  • -

#3 ishkabible  Icon User is offline

  • spelling expret
  • member icon




Reputation: 1622
  • View blog
  • Posts: 5,709
  • Joined: 03-August 09

Re: decltype expression can't use member from publicly inherited base

Posted 12 June 2012 - 08:01 AM

that definitely fixes it

never-mind; "templates", I missed that part. thanks! that makes sense. so if I inherit from a member in a template I have to explicitly specify the inherited member I'm referring to. I've never come across that issue before; I guess I always just used this->val in the few instances where I did something like this.

but in a member function I *should* be able access 'val'
just like 'x' in this example, I can print 'x' from bar's constructor.


#include<iostream>
 
struct foo {
   int x;
   foo() : x(3) {}
};
 
struct bar : public foo {
   bar() : foo() {
      std::cout<<x;
   }
};
 
int main() {
   bar x;
}



are the access rules different in methods than in class definition?

This post has been edited by ishkabible: 12 June 2012 - 08:18 AM

Was This Post Helpful? 0
  • +
  • -

#4 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2089
  • View blog
  • Posts: 3,181
  • Joined: 21-June 11

Re: decltype expression can't use member from publicly inherited base

Posted 12 June 2012 - 08:13 AM

As I said: "because of C++'s lookup rules regarding templates, you can't use inherited members unqualified". Specifically you can't use inherited members unqualified if you inherit from a templated class with non-fixed template arguments (i.e. it's fine when you inherit from foo<int>, but not when you inherit from foo<T>).

Your code example code doesn't contain any templates, so the problem does not apply. If you replace foo and bar in your example with templates, you'll get an error for using x on line 10 unless you replace it with this->x.
Was This Post Helpful? 0
  • +
  • -

#5 ishkabible  Icon User is offline

  • spelling expret
  • member icon




Reputation: 1622
  • View blog
  • Posts: 5,709
  • Joined: 03-August 09

Re: decltype expression can't use member from publicly inherited base

Posted 12 June 2012 - 08:14 AM

ya, I caught that just before you posted :P
Was This Post Helpful? 0
  • +
  • -

#6 ishkabible  Icon User is offline

  • spelling expret
  • member icon




Reputation: 1622
  • View blog
  • Posts: 5,709
  • Joined: 03-August 09

Re: decltype expression can't use member from publicly inherited base

Posted 14 June 2012 - 01:25 PM

I have another question on a similar issue; I want to determine the return type of a method that accepts an argument of arbitrary type and that type can only be known when a certain member function template is instantiated.

the following works:
class bar {
public:
	int blah(int y) {return y + 1;}
};

template<class B>
class foo {
private:
	B x;

	template<class>
	struct function_result;

	template<class R, class... Args>
	struct function_result<R(Args...)> {
		typedef R result_type;
	};

	template<class T>
	static auto get_ret_type(B x, T y)
		-> decltype(x.blah(y));
public:

	//using template alias I get the error 'get_ret_type' not declared in this scope
	//it appears that SFINAE seems to be the issue; it would appear
	template<class T>
	using ret_type = typename function_result<decltype(get_ret_type<T>)>::result_type;


	//template<class T>
	//struct ret_type {
		//typedef typename function_result<decltype(get_ret_type<T>)>::result_type type;
	//};

	template<class Int>
	ret_type<Int>
	test(Int y) {
		return x.blah(y);
	}

	/*
	//if 'x' was public I *could* do this but I want x to be private
	template<class Int>
	auto test(Int y) -> decltype(x.blah(y)) {
		return x.blah(y);
	}
	*/
};

int main() {
	std::cout<<(typeid(foo<bar>::ret_type<int>::type) == typeid(int));
}



but this doesn't:
#include <iostream>
#include <tuple>
#include <typeinfo>

template<int stop, int x, class Tuple>
struct tuple_print {
	tuple_print(const Tuple& t, std::ostream& out) {
		out<<std::get<x>(t)<<", ";
		tuple_print<stop, x + 1, Tuple>(t, out);
	}
};

template<int stop, class Tuple>
struct tuple_print<stop, stop, Tuple> {
	tuple_print(const Tuple& t, std::ostream& out) {
		out<<std::get<stop>(t)<<")";
	}
};

template<int stop, class Tuple>
struct tuple_print<stop, 0, Tuple> {
	tuple_print(const Tuple& t, std::ostream& out) {
		out<<"("<<std::get<0>(t)<<", ";
		tuple_print<stop, 1, Tuple>(t, out);
	}
};

template<class Tuple>
struct tuple_print<0, 0, Tuple> {
	tuple_print(const Tuple& t, std::ostream& out) {
		out<<"("<<std::get<0>(t)<<")";
	}
};

template<class... T>
std::ostream& operator<<(std::ostream& out, const std::tuple<T...>& t) {
	tuple_print<sizeof...(T) - 1, 0, std::tuple<T...>> x(t, out);
	return out;
}

template<class T, class... Tuple>
std::tuple<T, Tuple...> tuple_push(std::tuple<Tuple...>&& x, T&& y) {
	return std::move(std::tuple_cat(std::move(x), std::move(std::tuple<T>(std::move(y)))));
}

class bar {
public:
	int blah(int y) {return y + 1;}
};

template<class B>
class foo {
private:
	B x;

	template<class>
	struct function_result;

	template<class R, class... Args>
	struct function_result<R(Args...)> {
		typedef R result_type;
	};

	template<class T>
	static auto get_ret_type(B x, T y)
		-> decltype(x.blah(y));
public:

	//using template alias I get the error 'get_ret_type' not declared in this scope
	//it appears that SFINAE seems to be the issue; it would appear
	template<class T>
	using ret_type = typename function_result<decltype(get_ret_type<T>)>::result_type;


	//template<class T>
	//struct ret_type {
		//typedef typename function_result<decltype(get_ret_type<T>)>::result_type type;
	//};

	template<class Int>
	ret_type<Int>
	test(Int y) {
		return x.blah(y);
	}

	/*
	//if 'x' was public I *could* do this but I want x to be private
	template<class Int>
	auto test(Int y) -> decltype(x.blah(y)) {
		return x.blah(y);
	}
	*/
};

int main() {
	std::cout<<(typeid(foo<bar>::ret_type<int>::type) == typeid(int));
}



if I use a template alias, which is supposed to have the same semantics as the struct I made in the first example as near as I can tell, it gives me the error error: 'get_ret_type' was not declared in this scope. why is it doing this? O and if I use foo<B>::get_ret_type<T> it still doesn't work
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1