【问题标题】:type defined with using can't be used as function parameter使用 using 定义的类型不能用作函数参数
【发布时间】:2019-10-17 13:33:44
【问题描述】:

我在现实世界的应用程序中使用 CRTP 来构建或多或少的大类“堆栈”。我需要知道这些类的“公共基础”是什么,所以我在“堆栈”的一个类中定义了typeusing。后来我不想使用这个定义的类型作为模板函数参数,但这不起作用,我总是遇到“无法用 g++ 推导出模板参数'VAR_TYPE'”。

是否有机会解决这个问题,因为不建议手动定义类型,因为如果我的“类堆栈”的结构发生变化,应该可以自动更改。

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>*]
}

【问题讨论】:

    标签: c++ templates c++17 using


    【解决方案1】:

    遗憾的是,模板参数推导仅在直接上下文中有效,否则不合逻辑。想想那个例子:

    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
    }
    

    【讨论】:

    • 但是如果我必须使用重载来选择被调用的函数,我就不能先进入它。所以我通常必须考虑不同的设计......坏事但现实:-)
    • 重载也适用于这样的模板......除非我弄错了什么?第一步是什么意思?就像调试器中的第一个“Step in”之类的?
    • 我的示例显示了重载,并且无法通过从另一个模板内部使用来获取类型。所以我不能继续使用这种方法,因为我需要重载和定义“某处”的类型。一般来说,重载与模板一起工作是很清楚的...... ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    • 2022-01-26
    • 2011-10-27
    • 2013-07-02
    • 1970-01-01
    相关资源
    最近更新 更多