0

我正在尝试将检测添加到我的产品中广泛使用的模板类中。我目前正在VS 2019 (16.10.4)使用/std:c++17. 的新功能std::source_location对于我有兴趣解决的任务来说是一个很好的补充。虽然std::source_location并且std::experimental::source_location在我的编译器上不可用,但我根据这个答案构建了我自己的。我的目标是在特殊的构建和运行测试中更改类构造函数/成员。对类本身的更改不会改变其用法,因此其余代码保持不变。

这一切都可以编译并且效果很好 - 主要是。除了,我遇到了几乎超出使用目的的复制省略std::source_location。我希望我source_location成为定义调用者变量的位置,而不是创建实际对象的位置。

gcc -std=c++20这个问题也可以在有和没有的情况下得到证明-fno-elide-constructors。请参阅我的最小可重现Godbolt 示例的简化版本。

我的课:

class MyClass
{
private:
    int m_a = 0;
    std::source_location m_location;

public:
    MyClass(std::source_location location = std::source_location::current())
    : m_location(location)
    {
    }
    MyClass(const MyClass &other, std::source_location location = std::source_location::current())
    : m_a(other.m_a)
    , m_location(location)
    {
    }
    MyClass(MyClass &&other, std::source_location location = std::source_location::current())
    : m_a(other.m_a)
    , m_location(location)
    {
    }
};

用法:


MyClass getCopy1()
{
    MyClass ret;
    return ret;
}

MyClass getCopy2()
{
    return MyClass();
}

int main()
{
    MyClass o1;
    MyClass o2(o1);
    MyClass o3(getCopy1());
    MyClass o4(getCopy2());

    std::cout << "o1: " << o1.getLocationInfo() << std::endl;
    std::cout << "o2: " << o2.getLocationInfo() << std::endl;
    std::cout << "o3: " << o3.getLocationInfo() << std::endl;
    std::cout << "o4: " << o4.getLocationInfo() << std::endl;

    return 0;
}

实际输出:

o1: /app/example.cpp(56:13) int main()
o2: /app/example.cpp(57:18) int main()
o3: /app/example.cpp(46:12) MyClass getCopy1()
o4: /app/example.cpp(51:20) MyClass getCopy2()

预期输出:

o1: /app/example.cpp(56:13) int main()
o2: /app/example.cpp(57:18) int main()
o3: /app/example.cpp(58:26) int main()
o4: /app/example.cpp(59:26) int main()

解决方法 1(显式参数):

    MyClass o3(getCopy1(), std::source_location::current());
    MyClass o4(getCopy2(), std::source_location::current());

解决方法 2 ( std::move):

    MyClass o3(std::move(getCopy1()));
    MyClass o4(std::move(getCopy2()));

虽然上述任何解决方法都给了我想要的结果,但它们是不切实际的。这些将需要我更改使用代码的几个实例,并且会达到使用类似std::source_location. 对MyClass.h/cpp不破坏其使用的任何更改或对编译器标志的任何更改都是公平的游戏。我打算有一个不会在生产中使用的单独的检测构建。我的产品目前基于VS 2019 (16.10.4)./std:c++17

4

1 回答 1

1

你可以尝试这样的事情:

template <int line, std::size_t N, basic_fixed_string<N> file> 
class MyClassImpl {
   public:
      // copy from any instantiation 
      template <int line2, std::size_t N2, basic_fixed_string<N2> file2>
      MyClassImpl(const MyClassImpl<line2, N2, file2>& other) { ... }
      // also move, assignment etc
      ...
};

#define MyClass MyClassImpl<__LINE__, sizeof(__FILE__)-1, __FILE__>

你可以basic_fixed_string这里拿走或自己动手;如果可能的话,也可以随意使用您的实现来std::source_location代替旧式宏。这个想法是每次提到MyClass一个独特的类型。类定义中不使用模板参数,它们可以是任何东西,只要它们是唯一的。

现在不再有复制省略

MyClass o3(getCopy1());

因为类型不一样,所以没有要省略的副本。

当然,如果您使用,这根本不起作用auto

auto o3 = getCopy1(); // still has copy elision

所以这不是一个强大的解决方案。

于 2021-09-01T08:29:46.313 回答