分别依赖于模板参数的多个默认模板参数案例

multiple default template argument cases that depend on a template argument respectively

提问人:kaisong 提问时间:8/10/2023 更新时间:8/10/2023 访问量:45

问:

我想为模板类定义两个特定的默认情况。A

类似的事情可能吗?

template<typename T1, typename T2>
class A{
    // ...
};

struct X;
// if necessary, I can also define X right here.

template<>
A<X> = A<X,int>;

template<typename T>
A<T> = A<T,T>;

int main(){
    A<X> a;     // shall construct an instance of A<X,int>
    A<float> b; // shall construct an instance of A<float,float>
}

我了解如何通过使用 A 的派生来完成它。但是,我希望它也可以以与上面不起作用的片段中呈现的类似的直接方式实现。

c++ 默认模板参数

评论


答:

2赞 463035818_is_not_an_ai 8/10/2023 #1

如果是唯一可以使用的特殊情况:A<X,..>std::conditional_t

#include <type_traits>

template <typename T1,typename T2>
class A_impl {};

struct X {};

template<typename T1>
using A = A_impl<T1,std::conditional_t< std::is_same_v<T1,X>, int,T1>>;


int main(){
    A<X> a;     // shall construct an instance of A<X,int>
    A<float> b; // shall construct an instance of A<float,float>
}

我试图用 2 个模板参数保持您的完整。实际上,如果可能的话,我会放弃第二个参数,而是使用成员别名来表示何时总是从:AT2T2T1

#include <type_traits>

struct X {};

template<typename T1>
struct A {
    using T2 = std::conditional_t< std::is_same_v<T1,X>, int,T1>;
};


int main(){
    A<X> a;     // shall construct an instance of A<X,int>
    A<float> b; // shall construct an instance of A<float,float>
}

什么时候不是你仍然可以使用的唯一特殊情况,但它会很快变得毛茸茸的。对于从 到 的一般映射,我宁愿定义一个可以相应地专门化的特征:A<X,...>std::conditionalT1T2T2_from_T1_t

template<typename T1>
struct A {
    using T2 = T2_from_T1_t<T1>;
};

评论

0赞 kaisong 8/10/2023
感谢您的有用解决方案!你能用“成员别名”来解释你的提案吗?事实上,X 是我唯一需要条件的实例。
0赞 463035818_is_not_an_ai 8/10/2023
@kaisong它只是将我使用的类型移动到别名中,而不是将其插入 .查看编辑T2A_impl
1赞 Pepijn Kramer 8/10/2023 #2

您可以使用模板专用化来帮助您推断第二个参数的类型(这也可以很容易地扩展到其他专用化):

#include <type_traits>

namespace details
{
    // in allmost all cases we want to imply type int for the second argument
    template<typename type_t>
    struct deduced_second_arg_t_helper
    {
        using type = int;
    };

    // except for float, so use a template specialization to deduce a float
    template<>
    struct deduced_second_arg_t_helper<float>
    {
        using type = float;
    };

    // shorthand like 
    template<typename type_t>
    using deduced_second_arg_t = typename deduced_second_arg_t_helper<type_t>::type;
}

// now the second argument can be deduced from the first
template<typename type_t, typename second_arg_t = details::deduced_second_arg_t<type_t>>
struct A
{
    second_arg_t some_value;
};

// or simplified, we use the deduced type internally
template<typename type_t>
struct B
{
    using some_value_t = details::deduced_second_arg_t<type_t>;
    some_value_t some_value;
};

struct X
{
};

int main()
{
    A<X> a_x;
    A<float> a_f;
    static_assert(std::is_same_v<decltype(a_x.some_value), int>);
    static_assert(std::is_same_v<decltype(a_f.some_value), float>);

    B<X> b_x;
    B<float> b_f;
    static_assert(std::is_same_v<decltype(b_x.some_value), int>);
    static_assert(std::is_same_v<decltype(b_f.some_value), float>);

    return 0;
}

评论

0赞 kaisong 8/10/2023
也是一个非常漂亮的答案。当涉及到更复杂的条件时,它非常通用。谢谢
0赞 kaisong 8/10/2023 #3

根据 @463035818_is_not_an_ai 接受的答案,我看到可以通过将条件直接写入默认模板参数语法来缩短它:

struct X;

template<typename T1, typename T2 = std::is_same_v<X,T1>, int,T1> >
class A{
    // ...
};

int main(){
    A<X> a;     // shall construct an instance of A<X,int>
    A<float> b; // shall construct an instance of A<float,float>
}

评论

1赞 463035818_is_not_an_ai 8/10/2023
问题是你是否要启用 例如,即不是也不是的东西。这个答案允许它,我的在第一个版本中允许,但后来我明白你不需要它A<int,double>A<X,int>A<U,U>