问题
Note: the example provided in this question is not production code and has no sense at all. It is just there to illustrate my problem.
I was testing the possibilities of decltype
, especially if it is used to deduce function parameter types, and ran into a problem:
Suppose there were two classes structured like this:
struct ClassInt
{
// Note: no default ctor
ClassInt(int value)
: m_Value(value)
{}
int m_Value;
};
struct ClassDouble
{
// Note: no default ctor
ClassDouble(double value)
: m_Value(value)
{}
double m_Value;
};
Now, I wrote a function that (somehow) retrieves an instance of a the type parameter (which should be one of the above) by string and assigns a given value to its m_Value
member:
template< typename Ty >
Ty* get_fake_ptr() { return nullptr; }
// Retrieve pointer to Ty object by name and assign its value member.
// The problem is that we don't actually have an instance of Ty at the point
// where we want to define the type of the parameter "value".
template< typename Ty >
void assign(std::string name, decltype(get_fake_ptr<Ty>()->m_Value) value)
{
// Somehow get pointer to a Ty object by name
Ty* obj = ????;
// Assign
obj->m_Value = value;
}
Now, the type of the parameter value
is dependent on the type parameter, as the used classes differ in the type of the member m_Value
. As you can see, I solved it by using decltype
. Now, normally, you would use decltype
on a parameter, like this:
template<typename Ty>
void assign(Ty& obj, decltype(obj.m_Value) value);
But that is obviously not possible here since the actual instance is retrieved in the function body and is thus not available at the point where function arguments are declared.
I hacked it together by using the template function get_fake_ptr
which just returns a nullptr
of matching type so I have a "pseudo instance" that the compiler can use to determine the member type. And it works:
Now, as I said, this seems really hacky to me. So:
Is there a better way to solve this problem?
Thank you!
回答1:
You can use decltype(std::declval<T>().m_Value)
to deduce the type of T
's m_Value
member instead of using your get_fake_ptr()
function. They accomplish similar goals in the end.
By the way, your get_fake_ptr()
function does not need to be defined. You can simple leave it as template <typename T> T* get_fake_ptr();
and you can still use it inside decltype
.
回答2:
I see nothing wrong with this approach.
When it comes to template meta-programming, these kinds of "hacks" are par for the course.
I can suggest, though, a slightly different design pattern. Something like this:
struct ClassInt
{
// Note: no default ctor
ClassInt(int value)
: m_Value(value)
{}
typedef int m_value_t;
m_value_t m_Value;
};
struct ClassDouble
{
// Note: no default ctor
ClassDouble(double value)
: m_Value(value)
{}
typedef double m_value_t;
m_value_t m_Value;
};
// ...
template< typename Ty >
void assign(std::string name, typename Ty::value_t value)
{
// Somehow get pointer to a Ty object by name
Ty* obj = ????;
// Assign
obj->m_Value = value;
}
回答3:
Another alternative is to add another template parameter and just let the assignment handle matching types and conversions. Any non-convertable value types will generate a compile error.
template<typename Ty, typename VALUE_TYPE>
void assign(std::string name, VALUE_TYPE value) {
Ty* obj = ???
obj->m_Value = value;
}
来源:https://stackoverflow.com/questions/32686638/function-parameter-type-using-decltype