使用 using 定义的类型不能用作函数参数
type defined with using can't be used as function parameter
我在现实世界的应用程序中使用 CRTP 构建了一个或多或少的大 class "stack"。我需要知道这些 classes 的 "common base" 是什么,所以我在 "stack" 的 classes 中定义了一个 type
和 using
.稍后我不想将这个定义的类型用作模板函数参数,但这行不通,我总是 运行 到 "couldn't deduce template parameter 'VAR_TYPE'" with g++.
有没有机会解决这个问题,因为不建议手动定义类型,因为如果我的 "class stack" 的结构发生变化,应该可以自动更改。
template < typename T> struct B { using HERE = B<T>; };
template < typename T> struct C: public B<T> { };
template <typename T>
using COMMON_BASE = typename C<T>::HERE;
template < typename T>
void Print2( )
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
// g++ reports:
// error: no matching function for call to 'CheckMe(COMMON_BASE<int>*&)'
// note: candidate: 'template<class VAR_TYPE> void CheckMe(COMMON_BASE<VAR_TYPE>*)'
// note: template argument deduction/substitution failed:
// note: couldn't deduce template parameter 'VAR_TYPE'
template < typename VAR_TYPE >
void CheckMe( COMMON_BASE<VAR_TYPE>* ) { std::cout << "COMMON_BASE<>" << std::endl; }
// "hardcoded" works fine but should be avoided
//template < typename VAR_TYPE >
//void CheckMe( B<VAR_TYPE>* ) { std::cout << "B<>" << std::endl; }
void CheckMe( int* ) { std::cout << "int" << std::endl; }
//void CheckMe( ... ){ std::cout << "default" << std::endl; }
int main()
{
COMMON_BASE< int >* cb;
B<int>* bi;
CheckMe( cb );
CheckMe( bi );
Print2< COMMON_BASE<int>* >(); // gives: void Print2() [with T = B<int>*]
}
遗憾的是,模板参数推导仅适用于直接上下文,否则将不合逻辑。想想那个例子:
template<typename T>
using common_base = std::conditional<(sizeof(T) > 8), int, float>
template<typename T>
void call_me(common_base<T>) {
// ...
}
int main() {
call_me(1.4f); // What is T?
}
这看起来很明显,但这也是您的示例所发生的情况。你可以这样想象:
// Ah! Fooled you compiler!
template<> struct B<int> { using HERE = B<std::string>; };
那么之后,这些调用应该推导出什么?
CheckMe(bi); // should deduce B<int> or B<std::string>?
如您所见,编译器无法通过非直接上下文进行推导,因为可能没有 1:1 关系,有时甚至无法推导。
那你该怎么办?
简化模板函数是使其工作的常用方法:
template<typename T>
struct B {
using HERE = B<T>;
using type = T;
};
template<typename BaseType>
void CheckMe(BaseType* bt) {
using VAR_TYPE = BaseType::type; // yay, can use member type
}
我在现实世界的应用程序中使用 CRTP 构建了一个或多或少的大 class "stack"。我需要知道这些 classes 的 "common base" 是什么,所以我在 "stack" 的 classes 中定义了一个 type
和 using
.稍后我不想将这个定义的类型用作模板函数参数,但这行不通,我总是 运行 到 "couldn't deduce template parameter 'VAR_TYPE'" with g++.
有没有机会解决这个问题,因为不建议手动定义类型,因为如果我的 "class stack" 的结构发生变化,应该可以自动更改。
template < typename T> struct B { using HERE = B<T>; };
template < typename T> struct C: public B<T> { };
template <typename T>
using COMMON_BASE = typename C<T>::HERE;
template < typename T>
void Print2( )
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
// g++ reports:
// error: no matching function for call to 'CheckMe(COMMON_BASE<int>*&)'
// note: candidate: 'template<class VAR_TYPE> void CheckMe(COMMON_BASE<VAR_TYPE>*)'
// note: template argument deduction/substitution failed:
// note: couldn't deduce template parameter 'VAR_TYPE'
template < typename VAR_TYPE >
void CheckMe( COMMON_BASE<VAR_TYPE>* ) { std::cout << "COMMON_BASE<>" << std::endl; }
// "hardcoded" works fine but should be avoided
//template < typename VAR_TYPE >
//void CheckMe( B<VAR_TYPE>* ) { std::cout << "B<>" << std::endl; }
void CheckMe( int* ) { std::cout << "int" << std::endl; }
//void CheckMe( ... ){ std::cout << "default" << std::endl; }
int main()
{
COMMON_BASE< int >* cb;
B<int>* bi;
CheckMe( cb );
CheckMe( bi );
Print2< COMMON_BASE<int>* >(); // gives: void Print2() [with T = B<int>*]
}
遗憾的是,模板参数推导仅适用于直接上下文,否则将不合逻辑。想想那个例子:
template<typename T>
using common_base = std::conditional<(sizeof(T) > 8), int, float>
template<typename T>
void call_me(common_base<T>) {
// ...
}
int main() {
call_me(1.4f); // What is T?
}
这看起来很明显,但这也是您的示例所发生的情况。你可以这样想象:
// Ah! Fooled you compiler!
template<> struct B<int> { using HERE = B<std::string>; };
那么之后,这些调用应该推导出什么?
CheckMe(bi); // should deduce B<int> or B<std::string>?
如您所见,编译器无法通过非直接上下文进行推导,因为可能没有 1:1 关系,有时甚至无法推导。
那你该怎么办?
简化模板函数是使其工作的常用方法:
template<typename T>
struct B {
using HERE = B<T>;
using type = T;
};
template<typename BaseType>
void CheckMe(BaseType* bt) {
using VAR_TYPE = BaseType::type; // yay, can use member type
}