Reputation: 4555
I need to make the following work.
This is a reduced version of my actual code, but basically the difficulty is the same, i.e., to deduce the return type of a factory method.
Specifically, I need either the second or third variant of DeduceObjectT
(both commented), instead of the first, which requires the FactoryT::ObjectT
typedef.
#include <string>
#include <utility>
#include <memory>
template<class FactoryT>
using DeduceObjectT = typename FactoryT::ObjectT;
//template<class FactoryT>
//using DeduceObjectT = typename decltype(std::declval<FactoryT>().create())::element_type;
//template<class FactoryT>
//using DeduceObjectT = typename std::result_of<decltype(&FactoryT::create)(FactoryT)>::type::element_type;
template<class FactoryT>
struct FactoryUser
{
typedef DeduceObjectT<FactoryT> ObjectT;
};
template<class FactoryUserT>
struct Foo
{
typedef typename FactoryUserT::ObjectT ObjectT;
};
struct StringFactory
{
typedef std::string ObjectT; // want to omit this
std::unique_ptr<std::string> create()
{
return nullptr;
}
Foo<FactoryUser<StringFactory>> t;
};
int main()
{
StringFactory f;
return 0;
}
After numerous tries I still get 'error: invalid use of incomplete type ‘struct StringFactory’'.
I also tried deducing the type by means of a default template argument of FactoryUser
.
I really don't understand, why am I getting the error considering that the point that triggers instantiation of all templates is at the end -- the line that declares the data member t
.
Compiler is gcc 4.7.3. with -std=c++0x -O0
Upvotes: 2
Views: 1589
Reputation: 206657
You can alter Foo
a little bit for your code to work:
#include <string>
#include <utility>
#include <memory>
template<class FactoryT>
using DeduceObjectT = typename FactoryT::ObjectT;
template<class FactoryT>
struct FactoryUser
{
typedef DeduceObjectT<FactoryT> ObjectT;
};
// Provide a way for ObjectType to be specified at the time
// the template is instantiated.
template<class FactoryUserT, typename ObjectType = typename FactoryUserT::ObjectT>
struct Foo
{
typedef ObjectType ObjectT;
};
struct StringFactory
{
std::unique_ptr<std::string> create()
{
return nullptr;
}
Foo<FactoryUser<StringFactory>, std::string> t;
};
int main()
{
StringFactory f;
return 0;
}
Upvotes: 1
Reputation: 19118
Try something like this instead:
template <typename Factory>
struct ProductTypedef
{
typedef typename decltype(std::declval<Factory>().create())::element_type ObjectT;
};
struct StringFactory : public ProductTypedef<StringFactory> // CRTP
{
std::unique_ptr<std::string> create()
{
return nullptr;
}
};
Upvotes: 1