多个默认模板参数案例,分别依赖于一个模板参数。

huangapple go评论79阅读模式
英文:

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

问题

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

是否有类似的方法可行?:

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

struct X;
// 如果需要的话,我也可以在这里定义X。

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

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

int main(){
    A<X> a;     // 应该构造一个A<X,int>的实例;
    A<float> b; // 应该构造一个A<float,float>的实例;
}
英文:

I would like to define two particular default cases for a template class A.

Is something similar possible?:

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

I see how it can be done by using a derived of A. However, I would hope that it is also possible in a similarly straight-forward way to the one presented in the non-functioning snippet above.

答案1

得分: 2

If A<X,..> is the only special case you can use 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>
}

I tried to keep your A intact with 2 template arguments. Actually if possible, I would drop the second argument and instead use a member alias for T2 when T2 is always determined from T1:

#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>
}

When A&lt;X,...&gt; is not the only special case you can still use std::conditional but it will get hairy quickly. For a general mapping from T1 to T2 I'd rather define a trait T2_from_T1_t that can be specialized accordingly:

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

If A&lt;X,..&gt; is the only special case you can use std::conditional_t:

#include &lt;type_traits&gt;

template &lt;typename T1,typename T2&gt;
class A_impl {};

struct X {};

template&lt;typename T1&gt;
using A = A_impl&lt;T1,std::conditional_t&lt; std::is_same_v&lt;T1,X&gt;, int,T1&gt;&gt;;


int main(){
    A&lt;X&gt; a;     // shall construct an instance of A&lt;X,int&gt;
    A&lt;float&gt; b; // shall construct an instance of A&lt;float,float&gt;
}

I tried to keep your A intact with 2 template arguments. Actuallly if possible, I would drop the second argument and instead use a member alias for T2 when T2 is always determined from T1:

#include &lt;type_traits&gt;

struct X {};

template&lt;typename T1&gt;
struct A {
    using T2 = std::conditional_t&lt; std::is_same_v&lt;T1,X&gt;, int,T1&gt;;
};


int main(){
    A&lt;X&gt; a;     // shall construct an instance of A&lt;X,int&gt;
    A&lt;float&gt; b; // shall construct an instance of A&lt;float,float&gt;
}

When A&lt;X,...&gt; is not the only special case you can still use std::conditional but it will get hairy quickly. For a general mapping from T1 to T2 I'd rather define a trait T2_from_T1_t that can be specialized accordingly:

template&lt;typename T1&gt;
struct A {
    using T2 = T2_from_T1_t&lt;T1&gt;;
};

答案2

得分: 1

你可以使用模板特化来帮助你推断第二个参数的类型(这也可以轻松扩展到其他特化情况):

#include <type_traits>

namespace details
{
    // 在几乎所有情况下,我们希望第二个参数隐含为 int 类型
    template<typename type_t>
    struct deduced_second_arg_t_helper
    {
        using type = int;
    };

    // 除了 float,因此使用模板特化来推断为 float
    template<>
    struct deduced_second_arg_t_helper<float>
    {
        using type = float;
    };

    // 简写
    template<typename type_t>
    using deduced_second_arg_t = typename deduced_second_arg_t_helper<type_t>::type;
}

// 现在第二个参数可以从第一个参数中推断出来
template<typename type_t, typename second_arg_t = details::deduced_second_arg_t<type_t>>
struct A
{
    second_arg_t some_value;
};

// 或者简化,我们在内部使用推断的类型
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;
}

请注意,我只翻译了代码部分,不包括注释。

英文:

You can use template specialization to help you deduce the type of your second argument (this can easily be extended to other specializations too):

#include &lt;type_traits&gt;

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

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

	// shorthand like 
	template&lt;typename type_t&gt;
	using deduced_second_arg_t = typename deduced_second_arg_t_helper&lt;type_t&gt;::type;
}

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

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

struct X
{
};

int main()
{
	A&lt;X&gt; a_x;
	A&lt;float&gt; a_f;
	static_assert(std::is_same_v&lt;decltype(a_x.some_value), int&gt;);
	static_assert(std::is_same_v&lt;decltype(a_f.some_value), float&gt;);

	B&lt;X&gt; b_x;
	B&lt;float&gt; b_f;
	static_assert(std::is_same_v&lt;decltype(b_x.some_value), int&gt;);
	static_assert(std::is_same_v&lt;decltype(b_f.some_value), float&gt;);

	return 0;
}

答案3

得分: 0

根据@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;     // 应构造A<X,int>的实例
    A<float> b; // 应构造A<float,float>的实例
}
英文:

Based on @463035818_is_not_an_ai 's accepted answer, I saw it can be cut even shorter by writing the conditional directly into the default template argument syntax:

struct X;

template&lt;typename T1, typename T2 = std::is_same_v&lt;X,T1&gt;, int,T1&gt; &gt;
class A{
    // ...
};

int main(){
    A&lt;X&gt; a;     // shall construct an instance of A&lt;X,int&gt;
    A&lt;float&gt; b; // shall construct an instance of A&lt;float,float&gt;
}

huangapple
  • 本文由 发表于 2023年8月10日 21:43:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76876313.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定