参数包列表扩展导致可变参数构造函数重载失败

时间:2016-08-12 11:19:20

标签: c++

我有一个带有两个可变构造函数的结构,区别在于第二个构造函数前面有一个int const*参数:

struct S
{
    template<class... Args> S(Args... args)
    {
        int arr[sizeof...(args)] = { args... }; // [A]
    }
    template<class... Args> S(int const *p, Args... args) {} // [B]
};

int main()
{   
    int i = 1;
    S s(&i, 1, 2); // [C]
    return 0;
}

使用Visual C ++ 2015,行[A]会导致:error C2440: 'initializing': cannot convert from 'int *' to 'int'。如果我注释掉行[A]然后它编译精细和[C]调用[B],所以似乎初始化列表的存在导致编译器查看函数并变得贪婪尝试将所有参数转换为{{1忽略解释[B]。

如果我保留[A]但是将[C]中的构造函数调用更改为int,那么它也会编译好,所以[A]似乎阻止了从S s((int const*)&i, 1, 2);隐式转换为{{1通常适用于常规函数。

如果我不想在我的所有构造函数调用中显式const转换指针,而不是行[A]我可以使用递归函数将参数包解压缩到int数组中,但这更麻烦。最简单的解决方案就是将[B]更改为int*,但这样就隐藏了我不打算更改int const*的意图。

3 个答案:

答案 0 :(得分:1)

选择[A]的原因是因为参数包可以与int*完全匹配,因此不需要进行常量转换即可到达[B]。

一种选择是使用重载的助手来简单地提供一个&#34;值得到的&#34;您可以调用参数包:

int get_value_impl(int _in)
{
   return _in;
}

int get_value_impl(const int* _in)
{
   return *_in;
}


struct S
{
    template<class... Args> S(Args... args)
    {
        int arr[sizeof...(args)] = { get_value_impl(args)... }; // [A]
    }
};

int main()
{   
    int i = 1;
    S s(&i, 1, 2); // [C]
    return 0;
}

现在你根本不需要[B]。

如果您有更多类型,则可以向get_value_impl添加更多重载,并且您将保留S的结构。如果事情变得比这更复杂,您可能需要考虑使用SFINAE来选择get_value_impl的实现。我认为这个解决方案是一个更简单的标签调度。 Demo

答案 1 :(得分:0)

重载可变参数模板可能会变得非常噩梦。一种选择是添加一个重载,它将int*和委托给int const*构造函数:

template<class... Args> S(int *p, Args... args) : 
    S(static_cast<int const*>(p), args...) { }

如果您要传递大型课程,您可能需要考虑完美转发args

答案 2 :(得分:0)

这是因为它选择了你的第一个构造函数,而不是第二个构造函数。原因是,func writeF() { let file = "Sample.swift" let text = "import Foundation \n" + "public class Sample { \n" + " let v: Int = 0 \n" + "}" if let dir = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true).first { let path = NSURL(fileURLWithPath: dir).URLByAppendingPathComponent(file) //writing do { try text.writeToURL(path, atomically: false, encoding: NSUTF8StringEncoding) } catch {print("error writing file")} //reading do { let text2 = try NSString(contentsOfURL: path, encoding: NSUTF8StringEncoding) print(text2) } catch { print("error reading file") } } } 绑定到&i的引用。

你可以做的是使用type_traits来选择ctor,就像这样(C ++ 14):

int* const