英文:
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<X,...>
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<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. 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 <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<X,...>
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>;
};
答案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 <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;
}
答案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<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>
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论