How to conditionally define a lambda?





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







7















The following function will randomly "sprinkle salt" on a loaded image. For the sake of boosting performance, the conditional statement



uint j = rows == 1 ? 0 : randomRow(generator);


should not be inside the loop.



Instead, I want to define a lambda getJ before the loop as



auto getJ = rows == 1 ? () {return 0; } : () {return randomRow(generator); };


However, my code with this lambda does not compile with the following red squiggled text:



enter image description here



Question



How to conditionally define such a lambda?



void salt_(Mat mat, unsigned long long n)
{
const uchar channels = mat.channels();
uint cols = mat.cols;
uint rows = mat.rows;

if (mat.isContinuous())
{
cols *= rows;
rows = 1;
}

default_random_engine generator;
uniform_int_distribution<uint> randomRow(0, rows - 1);
uniform_int_distribution<uint> randomCol(0, cols - 1);



// auto getJ = rows == 1 ? () {return 0; } : () {return randomRow(generator); };


uchar * const data = mat.data;

for (unsigned long long counter = 0; counter < n; counter++)
{
uint i = randomCol(generator);
uint j = rows == 1 ? 0 : randomRow(generator);
//uint j = getJ();

uint index = channels * (cols * j + i);
for (uchar k = 0; k < channels; k++)
data[index + k] = 255;
}
}









share|improve this question




















  • 3





    "my code with this lambda does not compile" - What is the error you get?

    – Suma
    1 hour ago











  • You are trying to reference local variable generator without capturing it. If second lambda was capture-free it would compile.

    – VTT
    1 hour ago








  • 4





    Seems like a premature optimisation. Surely function call overhead would be greater than ternary overhead?

    – Artyer
    1 hour ago






  • 1





    Is a conditional really a performance issue here? Have you profiled the code?

    – Jesper Juhl
    1 hour ago






  • 1





    @Artyer Done well, the call to the lambda can be inlined.

    – Angew
    1 hour ago


















7















The following function will randomly "sprinkle salt" on a loaded image. For the sake of boosting performance, the conditional statement



uint j = rows == 1 ? 0 : randomRow(generator);


should not be inside the loop.



Instead, I want to define a lambda getJ before the loop as



auto getJ = rows == 1 ? () {return 0; } : () {return randomRow(generator); };


However, my code with this lambda does not compile with the following red squiggled text:



enter image description here



Question



How to conditionally define such a lambda?



void salt_(Mat mat, unsigned long long n)
{
const uchar channels = mat.channels();
uint cols = mat.cols;
uint rows = mat.rows;

if (mat.isContinuous())
{
cols *= rows;
rows = 1;
}

default_random_engine generator;
uniform_int_distribution<uint> randomRow(0, rows - 1);
uniform_int_distribution<uint> randomCol(0, cols - 1);



// auto getJ = rows == 1 ? () {return 0; } : () {return randomRow(generator); };


uchar * const data = mat.data;

for (unsigned long long counter = 0; counter < n; counter++)
{
uint i = randomCol(generator);
uint j = rows == 1 ? 0 : randomRow(generator);
//uint j = getJ();

uint index = channels * (cols * j + i);
for (uchar k = 0; k < channels; k++)
data[index + k] = 255;
}
}









share|improve this question




















  • 3





    "my code with this lambda does not compile" - What is the error you get?

    – Suma
    1 hour ago











  • You are trying to reference local variable generator without capturing it. If second lambda was capture-free it would compile.

    – VTT
    1 hour ago








  • 4





    Seems like a premature optimisation. Surely function call overhead would be greater than ternary overhead?

    – Artyer
    1 hour ago






  • 1





    Is a conditional really a performance issue here? Have you profiled the code?

    – Jesper Juhl
    1 hour ago






  • 1





    @Artyer Done well, the call to the lambda can be inlined.

    – Angew
    1 hour ago














7












7








7


1






The following function will randomly "sprinkle salt" on a loaded image. For the sake of boosting performance, the conditional statement



uint j = rows == 1 ? 0 : randomRow(generator);


should not be inside the loop.



Instead, I want to define a lambda getJ before the loop as



auto getJ = rows == 1 ? () {return 0; } : () {return randomRow(generator); };


However, my code with this lambda does not compile with the following red squiggled text:



enter image description here



Question



How to conditionally define such a lambda?



void salt_(Mat mat, unsigned long long n)
{
const uchar channels = mat.channels();
uint cols = mat.cols;
uint rows = mat.rows;

if (mat.isContinuous())
{
cols *= rows;
rows = 1;
}

default_random_engine generator;
uniform_int_distribution<uint> randomRow(0, rows - 1);
uniform_int_distribution<uint> randomCol(0, cols - 1);



// auto getJ = rows == 1 ? () {return 0; } : () {return randomRow(generator); };


uchar * const data = mat.data;

for (unsigned long long counter = 0; counter < n; counter++)
{
uint i = randomCol(generator);
uint j = rows == 1 ? 0 : randomRow(generator);
//uint j = getJ();

uint index = channels * (cols * j + i);
for (uchar k = 0; k < channels; k++)
data[index + k] = 255;
}
}









share|improve this question
















The following function will randomly "sprinkle salt" on a loaded image. For the sake of boosting performance, the conditional statement



uint j = rows == 1 ? 0 : randomRow(generator);


should not be inside the loop.



Instead, I want to define a lambda getJ before the loop as



auto getJ = rows == 1 ? () {return 0; } : () {return randomRow(generator); };


However, my code with this lambda does not compile with the following red squiggled text:



enter image description here



Question



How to conditionally define such a lambda?



void salt_(Mat mat, unsigned long long n)
{
const uchar channels = mat.channels();
uint cols = mat.cols;
uint rows = mat.rows;

if (mat.isContinuous())
{
cols *= rows;
rows = 1;
}

default_random_engine generator;
uniform_int_distribution<uint> randomRow(0, rows - 1);
uniform_int_distribution<uint> randomCol(0, cols - 1);



// auto getJ = rows == 1 ? () {return 0; } : () {return randomRow(generator); };


uchar * const data = mat.data;

for (unsigned long long counter = 0; counter < n; counter++)
{
uint i = randomCol(generator);
uint j = rows == 1 ? 0 : randomRow(generator);
//uint j = getJ();

uint index = channels * (cols * j + i);
for (uchar k = 0; k < channels; k++)
data[index + k] = 255;
}
}






c++






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 1 hour ago







Artificial Hairless Armpit

















asked 1 hour ago









Artificial Hairless ArmpitArtificial Hairless Armpit

1,2941535




1,2941535








  • 3





    "my code with this lambda does not compile" - What is the error you get?

    – Suma
    1 hour ago











  • You are trying to reference local variable generator without capturing it. If second lambda was capture-free it would compile.

    – VTT
    1 hour ago








  • 4





    Seems like a premature optimisation. Surely function call overhead would be greater than ternary overhead?

    – Artyer
    1 hour ago






  • 1





    Is a conditional really a performance issue here? Have you profiled the code?

    – Jesper Juhl
    1 hour ago






  • 1





    @Artyer Done well, the call to the lambda can be inlined.

    – Angew
    1 hour ago














  • 3





    "my code with this lambda does not compile" - What is the error you get?

    – Suma
    1 hour ago











  • You are trying to reference local variable generator without capturing it. If second lambda was capture-free it would compile.

    – VTT
    1 hour ago








  • 4





    Seems like a premature optimisation. Surely function call overhead would be greater than ternary overhead?

    – Artyer
    1 hour ago






  • 1





    Is a conditional really a performance issue here? Have you profiled the code?

    – Jesper Juhl
    1 hour ago






  • 1





    @Artyer Done well, the call to the lambda can be inlined.

    – Angew
    1 hour ago








3




3





"my code with this lambda does not compile" - What is the error you get?

– Suma
1 hour ago





"my code with this lambda does not compile" - What is the error you get?

– Suma
1 hour ago













You are trying to reference local variable generator without capturing it. If second lambda was capture-free it would compile.

– VTT
1 hour ago







You are trying to reference local variable generator without capturing it. If second lambda was capture-free it would compile.

– VTT
1 hour ago






4




4





Seems like a premature optimisation. Surely function call overhead would be greater than ternary overhead?

– Artyer
1 hour ago





Seems like a premature optimisation. Surely function call overhead would be greater than ternary overhead?

– Artyer
1 hour ago




1




1





Is a conditional really a performance issue here? Have you profiled the code?

– Jesper Juhl
1 hour ago





Is a conditional really a performance issue here? Have you profiled the code?

– Jesper Juhl
1 hour ago




1




1





@Artyer Done well, the call to the lambda can be inlined.

– Angew
1 hour ago





@Artyer Done well, the call to the lambda can be inlined.

– Angew
1 hour ago












2 Answers
2






active

oldest

votes


















7















my code with this lambda does not compile with the following red squiggled text




You cannot use randomRow inside the body of the lambda expression without capturing it beforehand, as the generated closure object needs to have access to it.



Even if you were to use [&randomRow], the code would still fail to compile as every lambda expression produces a closure of unique type, even if the lambda expressions are exactly the same.



You can turn the problem on its head to avoid any overhead and achieve what you want - create a function that takes the lambda you want to invoke:



template <typename F>
void saltImpl(F&& getJ, /* ... */)
{
uchar * const data = mat.data;

for (unsigned long long counter = 0; counter < n; counter++)
{
uint i = randomCol(generator);
uint j = rows == 1 ? 0 : randomRow(generator);
//uint j = getJ();

uint index = channels * (cols * j + i);
for (uchar k = 0; k < channels; k++)
data[index + k] = 255;
}
}


Usage example:



void salt_(Mat mat, unsigned long long n)
{
const uchar channels = mat.channels();
uint cols = mat.cols;
uint rows = mat.rows;

if (mat.isContinuous())
{
cols *= rows;
rows = 1;
}

default_random_engine generator;
uniform_int_distribution<uint> randomRow(0, rows - 1);
uniform_int_distribution<uint> randomCol(0, cols - 1);

if (rows == 1)
{
saltImpl({ return 0; }, /* ... */);
}
else
{
saltImpl([&]{ return randomRow(generator); }, /* ... */)
}
}





share|improve this answer


























  • Why not write a lambda that takes a lambda instead?

    – Yakk - Adam Nevraumont
    5 mins ago



















3














Why this fails is because the lambdas are of a different type. That's natural, their operator() have different definitions. Which means you want your following code to work with two different types. And the C++ way of making code work with different types is using templates.



Convert the code using getJ to a function template (it can be local to your implementation file), like this:



template <class G>
void salt_impl_(Mat mat, unsigned long long n, default_random_engine &generator, G getJ)
{
const uchar channels = mat.channels();
uint cols = mat.cols;
uint rows = mat.rows;

if (mat.isContinuous())
{
cols *= rows;
rows = 1;
}

uchar * const data = mat.data;

uniform_int_distribution<uint> randomCol(0, cols - 1);

for (unsigned long long counter = 0; counter < n; counter++)
{
uint i = randomCol(generator);
uint j = getJ();

uint index = channels * (cols * j + i);
for (uchar k = 0; k < channels; k++)
data[index + k] = 255;
}
}


void salt_(Mat mat, unsigned long long n)
{
const uchar channels = mat.channels();
uint cols = mat.cols;
uint rows = mat.rows;

if (mat.isContinuous())
{
cols *= rows;
rows = 1;
}

default_random_engine generator;
uniform_int_distribution<uint> randomRow(0, rows - 1);

if (rows == 1)
salt_impl_(mat, n, generator, () {return 0; });
else
salt_impl_(mat, n, generator, [&]() {return randomRow(generator); });
}


Feel free to reduce the initial-part duplication between the function and the template by passing more parameters, making them members of a class, or something similar.



Also note that the non-trivial lambda must capture the variables which it accesses (randomRow and generator). I did this using the universal by-reference capture [&] in the code above.






share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55708242%2fhow-to-conditionally-define-a-lambda%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    7















    my code with this lambda does not compile with the following red squiggled text




    You cannot use randomRow inside the body of the lambda expression without capturing it beforehand, as the generated closure object needs to have access to it.



    Even if you were to use [&randomRow], the code would still fail to compile as every lambda expression produces a closure of unique type, even if the lambda expressions are exactly the same.



    You can turn the problem on its head to avoid any overhead and achieve what you want - create a function that takes the lambda you want to invoke:



    template <typename F>
    void saltImpl(F&& getJ, /* ... */)
    {
    uchar * const data = mat.data;

    for (unsigned long long counter = 0; counter < n; counter++)
    {
    uint i = randomCol(generator);
    uint j = rows == 1 ? 0 : randomRow(generator);
    //uint j = getJ();

    uint index = channels * (cols * j + i);
    for (uchar k = 0; k < channels; k++)
    data[index + k] = 255;
    }
    }


    Usage example:



    void salt_(Mat mat, unsigned long long n)
    {
    const uchar channels = mat.channels();
    uint cols = mat.cols;
    uint rows = mat.rows;

    if (mat.isContinuous())
    {
    cols *= rows;
    rows = 1;
    }

    default_random_engine generator;
    uniform_int_distribution<uint> randomRow(0, rows - 1);
    uniform_int_distribution<uint> randomCol(0, cols - 1);

    if (rows == 1)
    {
    saltImpl({ return 0; }, /* ... */);
    }
    else
    {
    saltImpl([&]{ return randomRow(generator); }, /* ... */)
    }
    }





    share|improve this answer


























    • Why not write a lambda that takes a lambda instead?

      – Yakk - Adam Nevraumont
      5 mins ago
















    7















    my code with this lambda does not compile with the following red squiggled text




    You cannot use randomRow inside the body of the lambda expression without capturing it beforehand, as the generated closure object needs to have access to it.



    Even if you were to use [&randomRow], the code would still fail to compile as every lambda expression produces a closure of unique type, even if the lambda expressions are exactly the same.



    You can turn the problem on its head to avoid any overhead and achieve what you want - create a function that takes the lambda you want to invoke:



    template <typename F>
    void saltImpl(F&& getJ, /* ... */)
    {
    uchar * const data = mat.data;

    for (unsigned long long counter = 0; counter < n; counter++)
    {
    uint i = randomCol(generator);
    uint j = rows == 1 ? 0 : randomRow(generator);
    //uint j = getJ();

    uint index = channels * (cols * j + i);
    for (uchar k = 0; k < channels; k++)
    data[index + k] = 255;
    }
    }


    Usage example:



    void salt_(Mat mat, unsigned long long n)
    {
    const uchar channels = mat.channels();
    uint cols = mat.cols;
    uint rows = mat.rows;

    if (mat.isContinuous())
    {
    cols *= rows;
    rows = 1;
    }

    default_random_engine generator;
    uniform_int_distribution<uint> randomRow(0, rows - 1);
    uniform_int_distribution<uint> randomCol(0, cols - 1);

    if (rows == 1)
    {
    saltImpl({ return 0; }, /* ... */);
    }
    else
    {
    saltImpl([&]{ return randomRow(generator); }, /* ... */)
    }
    }





    share|improve this answer


























    • Why not write a lambda that takes a lambda instead?

      – Yakk - Adam Nevraumont
      5 mins ago














    7












    7








    7








    my code with this lambda does not compile with the following red squiggled text




    You cannot use randomRow inside the body of the lambda expression without capturing it beforehand, as the generated closure object needs to have access to it.



    Even if you were to use [&randomRow], the code would still fail to compile as every lambda expression produces a closure of unique type, even if the lambda expressions are exactly the same.



    You can turn the problem on its head to avoid any overhead and achieve what you want - create a function that takes the lambda you want to invoke:



    template <typename F>
    void saltImpl(F&& getJ, /* ... */)
    {
    uchar * const data = mat.data;

    for (unsigned long long counter = 0; counter < n; counter++)
    {
    uint i = randomCol(generator);
    uint j = rows == 1 ? 0 : randomRow(generator);
    //uint j = getJ();

    uint index = channels * (cols * j + i);
    for (uchar k = 0; k < channels; k++)
    data[index + k] = 255;
    }
    }


    Usage example:



    void salt_(Mat mat, unsigned long long n)
    {
    const uchar channels = mat.channels();
    uint cols = mat.cols;
    uint rows = mat.rows;

    if (mat.isContinuous())
    {
    cols *= rows;
    rows = 1;
    }

    default_random_engine generator;
    uniform_int_distribution<uint> randomRow(0, rows - 1);
    uniform_int_distribution<uint> randomCol(0, cols - 1);

    if (rows == 1)
    {
    saltImpl({ return 0; }, /* ... */);
    }
    else
    {
    saltImpl([&]{ return randomRow(generator); }, /* ... */)
    }
    }





    share|improve this answer
















    my code with this lambda does not compile with the following red squiggled text




    You cannot use randomRow inside the body of the lambda expression without capturing it beforehand, as the generated closure object needs to have access to it.



    Even if you were to use [&randomRow], the code would still fail to compile as every lambda expression produces a closure of unique type, even if the lambda expressions are exactly the same.



    You can turn the problem on its head to avoid any overhead and achieve what you want - create a function that takes the lambda you want to invoke:



    template <typename F>
    void saltImpl(F&& getJ, /* ... */)
    {
    uchar * const data = mat.data;

    for (unsigned long long counter = 0; counter < n; counter++)
    {
    uint i = randomCol(generator);
    uint j = rows == 1 ? 0 : randomRow(generator);
    //uint j = getJ();

    uint index = channels * (cols * j + i);
    for (uchar k = 0; k < channels; k++)
    data[index + k] = 255;
    }
    }


    Usage example:



    void salt_(Mat mat, unsigned long long n)
    {
    const uchar channels = mat.channels();
    uint cols = mat.cols;
    uint rows = mat.rows;

    if (mat.isContinuous())
    {
    cols *= rows;
    rows = 1;
    }

    default_random_engine generator;
    uniform_int_distribution<uint> randomRow(0, rows - 1);
    uniform_int_distribution<uint> randomCol(0, cols - 1);

    if (rows == 1)
    {
    saltImpl({ return 0; }, /* ... */);
    }
    else
    {
    saltImpl([&]{ return randomRow(generator); }, /* ... */)
    }
    }






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 58 mins ago

























    answered 1 hour ago









    Vittorio RomeoVittorio Romeo

    59.7k17165309




    59.7k17165309













    • Why not write a lambda that takes a lambda instead?

      – Yakk - Adam Nevraumont
      5 mins ago



















    • Why not write a lambda that takes a lambda instead?

      – Yakk - Adam Nevraumont
      5 mins ago

















    Why not write a lambda that takes a lambda instead?

    – Yakk - Adam Nevraumont
    5 mins ago





    Why not write a lambda that takes a lambda instead?

    – Yakk - Adam Nevraumont
    5 mins ago













    3














    Why this fails is because the lambdas are of a different type. That's natural, their operator() have different definitions. Which means you want your following code to work with two different types. And the C++ way of making code work with different types is using templates.



    Convert the code using getJ to a function template (it can be local to your implementation file), like this:



    template <class G>
    void salt_impl_(Mat mat, unsigned long long n, default_random_engine &generator, G getJ)
    {
    const uchar channels = mat.channels();
    uint cols = mat.cols;
    uint rows = mat.rows;

    if (mat.isContinuous())
    {
    cols *= rows;
    rows = 1;
    }

    uchar * const data = mat.data;

    uniform_int_distribution<uint> randomCol(0, cols - 1);

    for (unsigned long long counter = 0; counter < n; counter++)
    {
    uint i = randomCol(generator);
    uint j = getJ();

    uint index = channels * (cols * j + i);
    for (uchar k = 0; k < channels; k++)
    data[index + k] = 255;
    }
    }


    void salt_(Mat mat, unsigned long long n)
    {
    const uchar channels = mat.channels();
    uint cols = mat.cols;
    uint rows = mat.rows;

    if (mat.isContinuous())
    {
    cols *= rows;
    rows = 1;
    }

    default_random_engine generator;
    uniform_int_distribution<uint> randomRow(0, rows - 1);

    if (rows == 1)
    salt_impl_(mat, n, generator, () {return 0; });
    else
    salt_impl_(mat, n, generator, [&]() {return randomRow(generator); });
    }


    Feel free to reduce the initial-part duplication between the function and the template by passing more parameters, making them members of a class, or something similar.



    Also note that the non-trivial lambda must capture the variables which it accesses (randomRow and generator). I did this using the universal by-reference capture [&] in the code above.






    share|improve this answer




























      3














      Why this fails is because the lambdas are of a different type. That's natural, their operator() have different definitions. Which means you want your following code to work with two different types. And the C++ way of making code work with different types is using templates.



      Convert the code using getJ to a function template (it can be local to your implementation file), like this:



      template <class G>
      void salt_impl_(Mat mat, unsigned long long n, default_random_engine &generator, G getJ)
      {
      const uchar channels = mat.channels();
      uint cols = mat.cols;
      uint rows = mat.rows;

      if (mat.isContinuous())
      {
      cols *= rows;
      rows = 1;
      }

      uchar * const data = mat.data;

      uniform_int_distribution<uint> randomCol(0, cols - 1);

      for (unsigned long long counter = 0; counter < n; counter++)
      {
      uint i = randomCol(generator);
      uint j = getJ();

      uint index = channels * (cols * j + i);
      for (uchar k = 0; k < channels; k++)
      data[index + k] = 255;
      }
      }


      void salt_(Mat mat, unsigned long long n)
      {
      const uchar channels = mat.channels();
      uint cols = mat.cols;
      uint rows = mat.rows;

      if (mat.isContinuous())
      {
      cols *= rows;
      rows = 1;
      }

      default_random_engine generator;
      uniform_int_distribution<uint> randomRow(0, rows - 1);

      if (rows == 1)
      salt_impl_(mat, n, generator, () {return 0; });
      else
      salt_impl_(mat, n, generator, [&]() {return randomRow(generator); });
      }


      Feel free to reduce the initial-part duplication between the function and the template by passing more parameters, making them members of a class, or something similar.



      Also note that the non-trivial lambda must capture the variables which it accesses (randomRow and generator). I did this using the universal by-reference capture [&] in the code above.






      share|improve this answer


























        3












        3








        3







        Why this fails is because the lambdas are of a different type. That's natural, their operator() have different definitions. Which means you want your following code to work with two different types. And the C++ way of making code work with different types is using templates.



        Convert the code using getJ to a function template (it can be local to your implementation file), like this:



        template <class G>
        void salt_impl_(Mat mat, unsigned long long n, default_random_engine &generator, G getJ)
        {
        const uchar channels = mat.channels();
        uint cols = mat.cols;
        uint rows = mat.rows;

        if (mat.isContinuous())
        {
        cols *= rows;
        rows = 1;
        }

        uchar * const data = mat.data;

        uniform_int_distribution<uint> randomCol(0, cols - 1);

        for (unsigned long long counter = 0; counter < n; counter++)
        {
        uint i = randomCol(generator);
        uint j = getJ();

        uint index = channels * (cols * j + i);
        for (uchar k = 0; k < channels; k++)
        data[index + k] = 255;
        }
        }


        void salt_(Mat mat, unsigned long long n)
        {
        const uchar channels = mat.channels();
        uint cols = mat.cols;
        uint rows = mat.rows;

        if (mat.isContinuous())
        {
        cols *= rows;
        rows = 1;
        }

        default_random_engine generator;
        uniform_int_distribution<uint> randomRow(0, rows - 1);

        if (rows == 1)
        salt_impl_(mat, n, generator, () {return 0; });
        else
        salt_impl_(mat, n, generator, [&]() {return randomRow(generator); });
        }


        Feel free to reduce the initial-part duplication between the function and the template by passing more parameters, making them members of a class, or something similar.



        Also note that the non-trivial lambda must capture the variables which it accesses (randomRow and generator). I did this using the universal by-reference capture [&] in the code above.






        share|improve this answer













        Why this fails is because the lambdas are of a different type. That's natural, their operator() have different definitions. Which means you want your following code to work with two different types. And the C++ way of making code work with different types is using templates.



        Convert the code using getJ to a function template (it can be local to your implementation file), like this:



        template <class G>
        void salt_impl_(Mat mat, unsigned long long n, default_random_engine &generator, G getJ)
        {
        const uchar channels = mat.channels();
        uint cols = mat.cols;
        uint rows = mat.rows;

        if (mat.isContinuous())
        {
        cols *= rows;
        rows = 1;
        }

        uchar * const data = mat.data;

        uniform_int_distribution<uint> randomCol(0, cols - 1);

        for (unsigned long long counter = 0; counter < n; counter++)
        {
        uint i = randomCol(generator);
        uint j = getJ();

        uint index = channels * (cols * j + i);
        for (uchar k = 0; k < channels; k++)
        data[index + k] = 255;
        }
        }


        void salt_(Mat mat, unsigned long long n)
        {
        const uchar channels = mat.channels();
        uint cols = mat.cols;
        uint rows = mat.rows;

        if (mat.isContinuous())
        {
        cols *= rows;
        rows = 1;
        }

        default_random_engine generator;
        uniform_int_distribution<uint> randomRow(0, rows - 1);

        if (rows == 1)
        salt_impl_(mat, n, generator, () {return 0; });
        else
        salt_impl_(mat, n, generator, [&]() {return randomRow(generator); });
        }


        Feel free to reduce the initial-part duplication between the function and the template by passing more parameters, making them members of a class, or something similar.



        Also note that the non-trivial lambda must capture the variables which it accesses (randomRow and generator). I did this using the universal by-reference capture [&] in the code above.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 1 hour ago









        AngewAngew

        135k11261354




        135k11261354






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55708242%2fhow-to-conditionally-define-a-lambda%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Сан-Квентин

            8-я гвардейская общевойсковая армия

            Алькесар