有没有办法接受来自一个元素初始值设定项列表而不是单个值的隐式转换?
Is there any ways to accept implicit conversion from one element initializer list but not a single value?
这个问题本身可能比较混乱,所以我在这里详细描述一下。假设我们有一个类型 S
表示一维向量(线性代数向量,而不是 std
向量)。因为它是一种数组,所以如果它的行为类似于 std::array<int, 1>
就好了。显然,我们不希望仅使用标量进行构造,但应该允许从单个元素进行隐式列表初始化。以下代码片段中显示的是少数 initialization/conversion 场景,我更喜欢 #2 和 #4 工作,而拒绝 #1 和 #3。
struct S
{
explicit(?) S(int value);
};
S f1() { return 0; } // #1
S f2() { return { 0 }; } // #2
void g()
{
S s1 = 0; // #3
S s2{ 0 }; // #4
}
构造函数 explicit
将不允许 #1 和 #3,这很好,但作为副作用,它也不允许 #2。在这种情况下应该允许 #2,就像 std::array<int, 1>
的工作方式一样。
由于该类型将定义其他构造函数,并且我希望数据是私有的,所以据我所知,不可能使用与 std::array
相同的技术(聚合初始化 + 大括号省略)。有什么办法可以实现这个目标吗?我不介意一定要用一些奇葩的把戏
谢谢!
编辑:
- 我已经尝试
explicit(false) S(std::array<int, 1>);
并且它有效,但是对于案例 #2 和 #4 它需要一对额外的括号。如果不用额外的牙套也能达到同样的目的就好了。
这是不可能的。由于 S
不是聚合并且初始化列表不为空,因此您可以直接考虑 constructors for return {0};
。这与 return 0;
的(非列表)复制初始化相同的重载解决方案,只是不允许而不是忽略显式构造函数。
奇怪的是,这意味着您可以拥有 反向 行为:通过提供隐式和显式构造函数,这些构造函数对于从 int
构造是不明确的,您可以return {0};
由于具有 return 0;
select 转换构造函数时的歧义而失败。
人们可能会尝试涉及 中级 类型的技巧:
struct hold {hold(int);};
struct S {
S(hold);
};
不幸的是,多个用户定义的转换规则在复制初始化和复制列表初始化之间也是一致的,因此不会对任何一种构造模式尝试 S(hold(0))
解释。 (在某些情况下,多级大括号允许多个用户定义的转换,但根据假设,这与此处无关。)
这个问题本身可能比较混乱,所以我在这里详细描述一下。假设我们有一个类型 S
表示一维向量(线性代数向量,而不是 std
向量)。因为它是一种数组,所以如果它的行为类似于 std::array<int, 1>
就好了。显然,我们不希望仅使用标量进行构造,但应该允许从单个元素进行隐式列表初始化。以下代码片段中显示的是少数 initialization/conversion 场景,我更喜欢 #2 和 #4 工作,而拒绝 #1 和 #3。
struct S
{
explicit(?) S(int value);
};
S f1() { return 0; } // #1
S f2() { return { 0 }; } // #2
void g()
{
S s1 = 0; // #3
S s2{ 0 }; // #4
}
构造函数 explicit
将不允许 #1 和 #3,这很好,但作为副作用,它也不允许 #2。在这种情况下应该允许 #2,就像 std::array<int, 1>
的工作方式一样。
由于该类型将定义其他构造函数,并且我希望数据是私有的,所以据我所知,不可能使用与 std::array
相同的技术(聚合初始化 + 大括号省略)。有什么办法可以实现这个目标吗?我不介意一定要用一些奇葩的把戏
谢谢!
编辑:
- 我已经尝试
explicit(false) S(std::array<int, 1>);
并且它有效,但是对于案例 #2 和 #4 它需要一对额外的括号。如果不用额外的牙套也能达到同样的目的就好了。
这是不可能的。由于 S
不是聚合并且初始化列表不为空,因此您可以直接考虑 constructors for return {0};
。这与 return 0;
的(非列表)复制初始化相同的重载解决方案,只是不允许而不是忽略显式构造函数。
奇怪的是,这意味着您可以拥有 反向 行为:通过提供隐式和显式构造函数,这些构造函数对于从 int
构造是不明确的,您可以return {0};
由于具有 return 0;
select 转换构造函数时的歧义而失败。
人们可能会尝试涉及 中级 类型的技巧:
struct hold {hold(int);};
struct S {
S(hold);
};
不幸的是,多个用户定义的转换规则在复制初始化和复制列表初始化之间也是一致的,因此不会对任何一种构造模式尝试 S(hold(0))
解释。 (在某些情况下,多级大括号允许多个用户定义的转换,但根据假设,这与此处无关。)